6

質問

C++ 標準は、派生クラスのデストラクタが実行された後、基本クラスのデストラクタが実行される前のオブジェクトの状態について何を保証しますか? (これは、派生クラスのサブオブジェクトのデストラクタが呼び出されている時間です。)

#include <string>
struct Base;

struct Member {
  Member(Base *b);
  ~Member();
  Base *b_;
};

struct Base {
  virtual void f() {}
  virtual ~Base() {}
};

struct Derived : Base {
  Derived() : m(this) {}
  virtual ~Derived() {}  
  virtual void f() {}
  std::string s; 
  Member m;
};

Member::Member(Base *b) : b_(b) {}
Member::~Member() {
  // At this point, ~Derived has finished -- can we use b_ as a 
  // Derived* object (i.e. call Derived::f or access Derived::s)?
  b_->f();
}

int main() {
  Base *bd = new Derived;
  delete bd;
}

この例では、Memberオブジェクトはそれを所有するオブジェクトへのポインターを持っており、デストラクタが既に終了しているにもかかわらず、そのオブジェクトが破壊されるとDerived、そのオブジェクトにアクセスしようとします。DerivedDerived

一部のサブオブジェクトが実行後、実行前に*bd仮想関数を呼び出した場合、 の仮想関数のどのバージョンが呼び出されるでしょうか? その状態にあるときにアクセスすることは合法ですか?~Derived()~Base()*bd

4

3 に答える 3

5

私にとって、[12.4] から、それは合法ではないことは明らかです。

オブジェクトに対してデストラクタが呼び出されると、そのオブジェクトは存在しなくなります。有効期間が終了したオブジェクトに対してデストラクタが呼び出された場合の動作は未定義です (3.8)。[例: ...]

もはや存在しないの定義がないにもかかわらず、もはや存在しないオブジェクトを参照すると、未定義の動作が発生すると言えると思います。

于 2012-06-27T22:07:54.373 に答える
1

n3290 より [class.cdtor]

12.7 構築と破棄 1 自明でないコンストラクタを持つオブジェクトの場合、コンストラクタが実行を開始する前にオブジェクトの非静的メンバーまたは基本クラスを参照すると、未定義の動作が発生します。自明でないデストラクタを持つオブジェクトの場合、デストラクタが実行を終了した後にオブジェクトの非静的メンバーまたは基本クラスを参照すると、未定義の動作が発生します。

于 2012-06-28T00:30:33.510 に答える
1

あなたが電話している時点でb_->f()Derivedは破壊されていますが、Baseまだ破壊されていません。ただし、Derived::f()電話をかけるのはあなただからです。

編集:

仮想関数 (10.3) を含むメンバー関数は、構築または破棄 (12.6.2) 中に呼び出すことができます。仮想関数がコンストラクター (データ メンバーの mem-initializer からを含む) またはデストラクターから直接または間接的に呼び出され、呼び出しが適用されるオブジェクトが構築中または破棄中のオブジェクトである場合、呼び出される関数は、コンストラクタまたはデストラクタ自身のクラスまたはそのベースの 1 つで定義されたもの。ただし、コンストラクタまたはデストラクタのクラスから派生したクラスでそれをオーバーライドする関数、または最も派生したオブジェクトの他の基本クラスの 1 つでそれをオーバーライドする関数 (1.8 )。仮想関数呼び出しが明示的なクラス メンバー アクセスを使用する場合 (5.2.

C++0x ワーキング ドラフト Sec 12.7 par 4

于 2012-06-27T22:03:10.387 に答える