32

クラス コンストラクター内から "this" をポインターとして関数に渡し、それを使用してコンストラクターが戻る前にオブジェクトのメンバーを指すことはできますか?

アクセスされたメンバーが関数呼び出しの前に適切に初期化されている限り、これを行うのは安全ですか?

例として:

#include <iostream>

class Stuff
{
public:
    static void print_number(void *param)
    {
        std::cout << reinterpret_cast<Stuff*>(param)->number;
    }

    int number;

    Stuff(int number_)
        : number(number_)
    {
        print_number(this);
    }
};

void main() {
    Stuff stuff(12345);
}

これはうまくいかないと思っていましたが、うまくいくようです。これは標準的な動作ですか、それとも未定義の動作だけですか?

4

4 に答える 4

33

C++ でオブジェクトをインスタンス化すると、コンストラクター内のコードが最後に実行されます。スーパークラスの初期化、スーパークラスのコンストラクターの実行、メモリの割り当てなど、他のすべての初期化は事前に行われます。コンストラクターのコードは、オブジェクトが構築された後に追加の初期化を実行するだけです。したがって、クラスのコンストラクターで「this」ポインターを使用し、それが完全に構築されたオブジェクトを指していると想定することは完全に有効です。

もちろん、コンストラクター コードでメンバー変数をまだ初期化していない場合は、初期化されていないメンバー変数に注意する必要があります。

于 2009-01-14T23:49:46.813 に答える
4

これに対する適切な回答は、こちら(C++ FAQ) にあります。

継承されたすべてのメンバーと呼び出し元のクラスのメンバーは、コンストラクターのコード実行の開始時に構築されていることが保証されているため、コンストラクター内で安全に参照できます。

主な落とし穴は、 で仮想関数を呼び出すべきではないということですthis。私がこれを試したほとんどの場合、基本クラスの関数を呼び出すだけですが、標準では結果が未定義であると書かれていると思います。

于 2009-01-14T23:52:49.087 に答える
0

提示されたコードの補足として、代わりに次をテンプレート化しvoid*ます。

class Stuff
{
public:
    template <typename T>
    static void print_number(const T& t)
    {
        std::cout << t.number;
    }

    int number;

    Stuff(int number_)
    : number(number_)
    {
        print_number(*this);
    }
};

の型にメンバーtがない場合は、コンパイル エラーが発生します。number

于 2009-01-15T09:32:14.063 に答える
-2

アンディ、私はあなたが標準の未定義の部分について間違っていると思います。

コンストラクターを使用している場合、「this」は、作成しているオブジェクトの基本クラスを型とするオブジェクトへのポインターです。つまり、基本クラスに部分的に実装されている仮想関数が呼び出され、仮想テーブルはフォローされません。

C ++FaqLiteの詳細...

于 2009-01-15T08:12:46.360 に答える