0

次のコードがあります。

struct Message
{
   explicit Message(const std::string& message) : selfMessage(message) {};
   ~Message() { std::cerr << "Message: " << selfMessage << std::endl; }
   const std::string selfMessage;
};

struct Foo
{
   Foo() : fooMessage("Foo") {}
   /// Destructor here is left intentionally non-virtual !!!
   ~Foo() { std::cerr << "~Foo" << std::endl; }

   Message fooMessage;
};

struct Bar : Foo
{
   Bar() : barMessage("Bar") {}
   ~Bar() { std::cerr << "~Bar" << std::endl; }
   Message barMessage;
};

int main()
{
  std::auto_ptr<Foo> foo(new Bar);
}

次の出力が期待されます。

Message: Bar
Message: Foo
~Foo()

しかし、実際には (コードは でコンパイルされます) は、正しく破壊されていないことを理解している限り、gcc印刷されません。なんで?Message: BarbarMessage

私の知る限り、非仮想 d-tor は派生クラスの dtor の呼び出しにのみ影響します。呼び出されることはありませんが、派生クラスのスタック割り当てメンバーはどうですか?

ありがとうございました、

PS私はすでに非推奨の使用法について知っていstd::auto_ptr<>()ます:)

4

3 に答える 3

5

delete基本クラス オブジェクトへのポインタを介して派生オブジェクトを呼び出すと、基本クラスのデストラクタが virtual と宣言されていない限り、未定義の動作が発生します。

基本クラスが派生クラス オブジェクトを所有している場合に、その基本クラスでstd::auto_ptrテンプレート化されたオブジェクトをスコープ外に移動させると、実際のオブジェクトが派生クラス型である場合に、基本クラスのポインター型で delete を呼び出す効果があります。

于 2012-03-13T11:18:56.090 に答える
2

最終的に、auto_ptr呼び出しますdelete myPtr(ここmyPtrで、 は type のメンバーですT*)。静的delete型と動的型が同じでない呼び出しは、未定義の動作です。派生クラスのデストラクタが呼び出されない場合だけではありません。ほぼ何でも起こり得るケースです。また、より複雑な継承階層の場合も同様です。

これは、動的に割り当てられたインスタンスにのみ関連します。動的に割り当てられていないものに対して削除を呼び出すと、未定義の動作になります (通常、あらゆる種類の問題が発生します)。また、削除を除いて、デストラクタはポインタではなくオブジェクトに対して呼び出されるため、静的型と動的型は同じです。

于 2012-03-13T11:23:36.713 に答える
1

Bar::barMessageベースのデストラクトが仮想ではないため、正確には破壊されません。ポインターはタイプFooであり、スコープを終了すると、未定義の動作である内部ポインターでstd::auto_ptrdill 呼び出しが行われ、この場合、サブオブジェクトのみが破棄されます。deleteFoo

のスタックに割り当てられたメンバーなどはなくBar、自動ストレージを持つメンバーがありますが、この場合、オブジェクト全体が動的に割り当てられているため、スタックではなくヒープにあることに注意してください(C++ には技術的にはスタック/ヒープですが、すべてのBarオブジェクトが動的に割り当てられることを理解してください)

于 2012-03-13T11:25:05.707 に答える