11

これは安全ですか?実際の実装では仮想関数を使用していませんが、使用したとしても安全であると信じたくなりました。

class Foo
{
    Foo()
    {
        // initialize things
    }

    Foo( int )
    {
         new ( this ) Foo();
    }
}
4

7 に答える 7

13

コンストラクターの開いた中括弧を入力するまでにFoo(int)、すべてのクラスメンバーのコンストラクターが呼び出されています。次に、配置がnewの別のコンストラクターを強制的に呼び出すと、クラスの現在の状態が上書きされます。これは基本的に、すべてのメンバーがコンストラクターを2回呼び出すことを意味します。コンストラクターで何かがnew行われると、そのコンテンツがリークされ、本当に本当に混乱します。 2つのオブジェクトを効果的に構築しており、2番目のオブジェクトが最初のオブジェクトのメモリを上書きするため、最初のオブジェクトのメンバーのデストラクタが呼び出されることはありません

言い換えれば、それは悪いです!やらないで!

最も一般的な回避策は、ある種の初期化関数を使用し、それを両方のコンストラクターから呼び出すことです。ただし、これでは、初期化子リストに含まれている必要があるconstメンバーやその他のメンバーを初期化することはできません。

于 2010-04-19T14:34:48.900 に答える
3

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3

于 2010-04-19T14:30:55.150 に答える
1

私が心配しているのは、Fooが多重継承を使用している場合、this最初に最も基本的なクラスへのポインターをキャストする必要があるということです。そうでなければ、thisがオフセットされている場合(多重継承で発生する場合があります)、間違ったアドレスで構築されます。

于 2010-04-19T14:32:34.870 に答える
1

たとえば、別のクラスを拡張し、そのクラスにデストラクタがあった場合、安全ではありません。

class Foo
{
    int* a;
public:
    Foo():a(new int)
    {

    }
    ~Foo(){delete a;}
}

class Bar:public Foo
{
    Bar()
    {
        // initialize things
    }

    Bar( int )
    {
         new ( this ) Foo();
    }
}

最初にBar(int)を呼び出しFoo()、次に、をBar()呼び出しますFoo()。2回目Foo()は、への最初の呼び出しで設定されたポインタを上書きしFoo()、割り当てられたメモリがリークされます。

于 2010-04-19T14:33:44.507 に答える
1

ここでの重要な問題は、コンストラクターが特別であるということです。コンストラクターを呼び出すコンストラクターを作成する場合(たとえば、newキーワードを使用してオブジェクトを作成する場合)、コンストラクター本体が実行されるだけでなく、オブジェクトのチェーン全体が最初に構築されます。

したがって、配置構文を使用して別のコンストラクターを最初に実行すると、C ++はすべての基本クラスオブジェクトコンストラクターとすべてのメンバー変数コンストラクターを自動的に再実行し、次に他のコンストラクター本体が呼び出されます。大丈夫な場合もありますが、多くの場合、予期しない動作に遭遇します。

于 2010-04-19T14:33:47.380 に答える
1

この問題の最善の解決策は、初期化を行う別の関数を作成することです。

class Foo
{
    inline void nullify()
    {
        // initialize things
    }

    Foo()
    {
        nullify();
    }

    Foo( int )
    {
        nullify();
    }
}
于 2010-04-19T14:40:15.017 に答える