1

重複の可能性:
ローカル変数のメモリにそのスコープ外でアクセスできますか?

コード:

#include <iostream>
using namespace std;

class B{
    public:
    int b;
    B():b(1){}
    ~B(){cout << "Destructor ~B() " << endl;}
};

class A{
    public:
    B ob;
    A()try{throw 4;}
    catch(...){cout << "Catched in A() handler : ob.b= " << ob.b<<endl;}
};




int main()try{
A t;


}
catch(...){cout << "CATCHED in Main" <<  endl;}

出力:

Destructor ~B() 
Catched in A() handler : ob.b= 1
CATCHED in Main

私の質問は、デストラクタ呼び出しが終了しbたオブジェクトのメンバー変数にアクセスする方法です。ob

4

3 に答える 3

8

破壊されたオブジェクトの使用は未定義の動作です。これは、あなたが今この振る舞いをしているかもしれないことを意味します、しかしあなたがいつかそれを得るという保証は何もありません。この例が示すように、未定義の動作は検出がより困難になる可能性があるため、通常のバグよりも危険です。

更新:いくつかのコメントに続いて、OPのコードがその出力を生成する理由を説明します。

try関数ブロックは、C++ではややあいまいな機能です。関数の本体全体tryを、対応する。で囲むことができcatchます。これは、代わりに:

void foo()
{
  try
  {
    //...
  }
  catch (/*whatever*/)
  {
    //...
  }
}

あなたは書ける:

void foo()
try
{
    //...
}
catch (/*whatever*/)
{
  //...
}

これは実際にはあまり有用ではありませんが、tryブロック内に初期化リストを含める唯一の方法であるため、コンストラクターにとってはわずかに有用です。したがって、AコンストラクターのOPのコードは次のようになります。

A()
try
: b()
{
  throw 4;
}
catch(...)
{
  cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
}

catchブロック内で作成しているオブジェクトを使用できないため、これはほんのわずかに役立つと言いました。ブロック内にスローするtryと、例外はコンストラクター本体を離れるため、オブジェクトは構築されておらず、構築されたデータメンバーはcatchブロックに入る前にすぐに破棄されます。ただし、ロギングの目的で使用できる場合があります。

さて、ご存知のとおり、コンストラクター(nothrowバージョンを使用していないと仮定)は2つのことしか実行できません。

  1. 構築されたオブジェクトを返す
  2. 例外をスローする

このコンストラクターではスローしますが、例外はcatchブロックでキャッチされます。では、今何が起こっているのでしょうか?コンストラクターを呼び出すコードには何が返されますか?構築されたオブジェクトがないため、オブジェクトを返すことはできません。そのため、選択肢は1つだけです。つまり、catchブロックをスローする必要があります。そして、これは実際にはこの場合の標準で義務付けられているものです。明示的にスローしない場合、コンパイラはブロックthrow;の最後に命令をサイレントに追加します。catchしたがって、もう少し詳しく説明すると、コンストラクターは次のようになります。

A()
try
: b()
{
  throw 4;
}
catch(...)
{
  cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
  throw;
}

そして、これが例外が2回キャッチされる理由です。1回はAコンストラクターで、もう1回はmain()

于 2012-10-25T11:42:29.143 に答える
3

オブジェクトが破壊されている間、それが占めていた実際のメモリはまだ存在しているからです。ただし、これは未定義の動作であり、機能する場合と機能しない場合があります。

于 2012-10-25T11:43:31.717 に答える
2

これはコンパイラのバグである可能性があります。

コードを実行すると、デストラクタが適切な順序で呼び出されます。出力は次のとおりです。

Catched in A() handler : ob.b= 1
Destructor ~B()

catchそして、なぜinmainが実行されるのか想像できません。例外はすでにキャッチされていA::A()ます。

アップデート

私は編集に混乱しました。もともと、違いを生むのは初期化子リストのtry/catch構文でした。これでOPの出力を再現でき、確かにUBです。クラッシュしました。

于 2012-10-25T11:55:20.930 に答える