12

CRTPの次の例を考えます。

template <typename T>
int foo(T* const)
{
   return 0;
}

template <typename Derived>
struct Base
{
   Base() : bar(foo(static_cast<Derived*>(this)) {};
   int bar;
};

struct Derived1 : Base<Derived1> {};

thisここへの変換はDerived*有効ですか?そうではないかもしれないことを思い出しているようですが、今のところ具体的な証拠を見つけることができません。

thisこの段階での「自然な」タイプはであり、ベースの構築が完了する前のアップキャスト(12.7 / 3)など、初期化中に静的にポインタをBase* constキャストしても問題がない場合が確かにあります。this

@DeadMGは言う:

イニシャライザリストでこれを取得する標準wrtには明示的な例外があります。これは、自分自身へのポインタをサブオブジェクトに渡すためのものです。

12.6.2 / 12は言う:

[注:mem-initializerはコンストラクターのスコープで評価されるため、このポインターをmem-initializerの式リストで使用して、初期化されるオブジェクトを参照できます。—エンドノート]

Derived*...これはへの変換が有効であると言うのに十分ではありませんが。

私の直感では、オブジェクトの初期化のこのフェーズでは、のインスタンスを指さないので、厳密に言えば、型でそのインスタンスへthisポインターを持っているだけDerivedでもUBです。これは、有効なポインタでもnullポインタでもないためです。Derived*

(これは、このようなアプローチに実際的な影響を与える可能性がありますが、その回答と上記の私の例では、代わりに単に書くことですべてを回避することができますstatic_cast<Derived*>(0)。)

4

1 に答える 1

4

UBだと思います。

マイクが言ったように:

その時点で、ストレージは完全なオブジェクトに割り当てられていますが、基本サブオブジェクトのみが初期化されています。したがって、オブジェクトの残りの部分は、C++11 で説明されている「限定された方法」でのみ使用できます。

これはそれらの方法の1つではないというのが私の解釈です。

より正式には:

[C++11: 3.8/1]:オブジェクトの有効期間は、オブジェクトのランタイム プロパティです。オブジェクトがクラスまたは集約型であり、それまたはそのメンバーの 1 つが自明なデフォルト コンストラクター以外のコンストラクターによって初期化される場合、そのオブジェクトは非自明な初期化を持つと言われます。[注:単純なコピー/移動コンストラクターによる初期化は、非自明な初期化です。— 終わりの注]型のオブジェクトの有効期間は、次のT時点で始まります。

  • タイプの適切な位置合わせとサイズのストレージTが取得されます。
  • オブジェクトに重要な初期化がある場合、その初期化は完了しています。

と:

[C++11: 3.8/5]: オブジェクトの有効期間が開始する前で、オブジェクトが占有するストレージが割り当てられた後、またはオブジェクトの有効期間が終了した後、オブジェクトが占有していたストレージが再利用または解放される前に、ストレージを参照するポインターオブジェクトが配置される、または配置された場所を使用できますが、限られた方法でのみ使用できます。建設中または破壊中のオブジェクトについては、12.7 を参照してください。それ以外の場合、そのようなポインターは割り当てられたストレージ (3.7.4.2) を参照し、ポインターが typevoid*であるかのようにポインターを使用することは明確に定義されています。このようなポインターは参照解除できますが、結果の左辺値は、以下で説明するように、限られた方法でのみ使用できます。次の場合、プログラムは未定義の動作をします。

  • オブジェクトが非自明なデストラクタを持つクラス型であるか、そうであり、ポインタが削除式のオペランドとして使用されている場合、
  • ポインターは、非静的データ メンバーにアクセスするか、オブジェクトの非静的メンバー関数を呼び出すために使用されます。
  • ポインターが基本クラス型へのポインターに暗黙的に変換される (4.10)、または
  • static_castポインターが(5.2.9)のオペランドとして使用されるvoid*(変換が、 または への変換でvoid*、その後にchar*、 またはである場合を除くunsigned char*)、または
  • ポインターはdynamic_cast [..]のオペランドとして使用されます。
于 2013-02-04T13:19:35.900 に答える