0

次のコードでは、subクラス内のオブジェクトがC2 回作成されます。最初の構成はデフォルトの ctor を呼び出し、 2 番目の構成は このオブジェクトを同じアドレスに再Sub()構築するために使用します。placement new

したがって、デストラクタも 2 回呼び出されます。Sub最初の呼び出しはdtorへの直接呼び出しを使用し~C()、2 番目の呼び出しは の終了後に関数main()によって呼び出されると思いatexit()ます。

オブジェクトsubが同じアドレスで再構築される場合、コンパイラは 2 番目のデストラクタを の後に呼び出す必要があることをどのように認識しmain()ますか? 彼はこの情報をどこに保管していますか?

#include <iostream>
using namespace std;

struct Table
{
    int i;
    Table(int j) : i(j) {}
};

struct Sub
{
    Table* pTable;
    Sub(int j) { cout << "ctor placement new" << endl; pTable = new Table(j); }
    Sub() { cout << "ctor default" << endl; pTable = 0; }
    ~Sub() { if( pTable ) cout << "dtor placement new" << endl;
             else         cout << "dtor default" << endl;
             delete pTable; pTable = 0; }
};

class C
{
    Sub sub;

    public:
    C() { new (&sub) Sub(10); }
    ~C() { (&sub)->~Sub(); }
};

int main()
{
    C c;
}
4

4 に答える 4

4

についてのあなたの仮定atexit()は間違っています。のデストラクタ forは、オブジェクトが のスコープ外に出たときに、 subfor のデストラクタによって呼び出されます。Ccmain()

C++ デストラクタは、常にそのすべてのサブオブジェクトに対してデストラクタを呼び出します。

subオブジェクトに既に構築されているメモリのチャンク ( ) で配置 new 演算子を呼び出しているため、コードはとにかく無効です。デストラクタと同様に、C++ コンストラクタは常にすべてのサブオブジェクトのコンストラクタを呼び出します。

于 2012-01-17T18:11:18.810 に答える
1

これは明らかに未定義の動作ですが、何が起こっているのかを理解すれば、かなり明白です。

クラス C のオブジェクトを作成します。そのプロセスでは、Sub の既定のコンストラクターが暗黙的に呼び出されます。pTable は 0 です。次に、pTable を初期化する int コンストラクターを明示的に呼び出します。次に、デストラクタで、Sub のデストラクタを明示的に呼び出します。pTable は再び 0 に設定されます。次に、C のデストラクタの最後で、Sub のデストラクタが暗黙的に再度呼び出されます。

それが起こっているのはメインの終わりではありません。Cのデストラクタの最後で起こっています。

于 2012-01-17T18:26:01.513 に答える
0

c がスコープ外になると、そのデストラクタが呼び出されます。C デストラクタは、サブ デストラクタを明示的に呼び出します。C デストラクタが完了すると、サブ デストラクタも (再び) 呼び出されます。これは、すべての C++ デストラクタが、すべての内部オブジェクトのデストラクタを自動的に呼び出すためです。

基本的に、コード

(&sub)->~Sub();

不要であり、正しくありません。管理対象オブジェクトのデストラクタを明示的に呼び出すべきではありません。

編集: 配置 new によって構築されたオブジェクトでデストラクタを明示的に呼び出すことは有効です。ただし、これはオブジェクトが管理されていない場合のみです。例えば:

class C
{
    Sub sub[1];

    public:
    C() { new (sub) Sub(10); }
    ~C() { sub->~Sub(); }
};

これは有効であるだけでなく、C のメンバーが Sub[1] (またはより一般的には Sub*) 型であるため、C が破棄されるときに Sub のデストラクタが明示的に呼び出されないために必要です。

于 2012-01-17T18:12:38.027 に答える