4

this次のようにメンバー変数に引数として渡したい:

template<class T>
struct fun
{
    fun(T* pointer) : memberPointer(pointer)
    {
    }
    T* memberPointer;
};

struct gun
{
    gun() : member(this)
    {
    }
    fun<gun> member;
};

Visual Studio では、次の警告があります。warning C4355: 'this' : used in base member initializer list

なぜこれを行うのが間違っているのか説明してもらえますか? ポインターをメンバーコンストラクターに保存して、後でそれを使用してgunからいくつかの関数を呼び出すだけfunです。

4

4 に答える 4

5

潜在的な問題は、this完全に構築されていないオブジェクトを指すことです。たとえば、これがあった場合:

template<class T>
struct fun
{
    fun(T* pointer) : memberPointer(pointer)
    {
        memberPointer->callMethod(); //this is 2nd to execute
    }

    T* memberPointer;
};

struct gun
{
    gun() : member(this) //this is 1st to execute
    {
       ptr = new char(); // this is 4rd to execute unless earlier UB prevents execution
    }
    void callMethod()
    {
       printf("%s", ptr); //this is 3rd to execute, you get UB here
    }
   fun<gun> member;
   char* ptr;
};

完全に構築されたオブジェクトへのポインターのみを渡す必要がある場合に、完全に構築されていないオブジェクトへのポインターを渡すため、未定義の動作が発生します。より説得力のあるものにするために、意図的に UB を使用してくだらないコードを作成しました。実際には、必ずしも UB が問題になるとは限りません。すべてのオブジェクトが有効な状態にある場合があるため、非常に微妙な初期化順序のバグが発生することがあります。

それはあなたの場合ではありません。あなたの場合は問題ありません-オブジェクトがまだ完全に構築されていなくてもかまいません。ただし、上記のようなシナリオに陥らないように、コードを変更するときは注意が必要です。

于 2013-04-04T07:13:24.600 に答える
1

それは単なる警告です。fun コンストラクターthis内で参照すると、初期化されていないオブジェクトにアクセスすることになります。しかし、そうではありません。ポインタを格納しているだけなので、警告を無視できます。警告をオフにしたい場合は、これをコードの先頭に追加します

#pragma warning (disable: 4355)
于 2013-04-04T07:14:26.627 に答える
0

完全に間違っているわけではありませんが、ポインターを渡すと、銃のオブジェクトがまだ完全に構築されていない可能性があります。したがって、オブジェクトの完全な構築に依存する基本クラスのメソッドを呼び出す場合があります。

于 2013-04-04T07:14:45.050 に答える
0

あなたが望むのは、静的ポリモーフィズムを実現することです。これは、奇妙に繰り返されるテンプレート パターン (CRTP)を使用して処理するのが最適です。あなたの場合、あなたはほとんどそこにいます:

template<class Base>
struct fun : public Base
{
    void foo()
    {
        // call gun function
        Base::bar();
    }
};

struct gun : public fun<gun>
{
    void bar()
    {
        /*...*/
    }
};
于 2013-04-04T07:20:00.067 に答える