簡単な質問ですが、次の問題はありません。
struct X
{
A& x;
A y;
X() : x(y) {}
};
構造体の2つのメンバーの順序を逆にすると、最初に初期化されることが保証されるため、間違いなく問題y
ありませんが、これは機能しますか、それともUBを呼び出しますか?
さらに、次のことは問題ありません。
struct X
{
X& x;
X() : x(*this) {}
};
?
それが未定義の振る舞いを引き起こすとは思わない。
私はその場合がこれと何ら違うとは思わない:
int *p = new int;
式は、初期化されていないintnew int
へのポインタです。ここでは、ポインタをで初期化しています。内容は読み込まれません。 p
new int
同様に、
int & r = *p; //or *new int
ここでは、を使用して参照 r
を初期化してい*p
ます。内容が読まれない
どちらの場合も、コンテンツは読み取られません。初期化されていない変数を読み取ると、未定義の動作が呼び出されます。どちらの場合も、アドレスではなく、初期化されていないコンテンツであり、コンテンツを読み取っていません。
参照と変数は別個のものであり、それぞれに独自の「初期化」があります。
参照の目的は、を参照することsomething
です。唯一の前提条件は、something
物理的に存在することです。その状態が明確に定義されているかどうかにかかわらず、すべて別の話です。
参照の初期化はUBではありません。参照するものに値が与えられる前は、UBで使用できますが、これは、初期化された変数を使用したときに得られるものと同じです。
別のものはX() :x(*this) {}
ここでは、まだ完全に構築されていないものへのポインターを関数(xコンストラクター)に与えています。これは「危険」です。なぜなら、一般に、その関数がそのポインターで何をするのか、そしてそれが何らかの形で「失敗」することを期待するかどうかわからないからです。それは単に「後で使用するために保存する」(したがって問題ありません)かもしれませんが、アクセスするためにそれを尊重するかもしれません...再構築されていないメンバー!これは、コンパイラが少なくとも警告する必要があるものです。
もちろん、この特定のケース(参照を初期化するだけです)では、「参照コンストラクター」は参照されたオブジェクトにアクセスしないため、問題にはなりません。しかし、一般的には良い考えではありません。
この問題を他のいくつかのポイントに分割することは理にかなっていると思います。
私は答えます:Y、Y、Y/N。
上記のコードのサンプルにはあいまいさは見られません。構文的に正しいコードがメモリを破壊したり、クラッシュしたりする方法は何百万もあります。これはさらに別の例です。
上記の例は明らかであるため、コンパイラは警告を発行する場合があります。間接化や再定義などが多い実際のシナリオでは、コンパイラーが混乱する可能性があります。私はそれをあまり強く非難しません。アルゴリズム分析は、コンパイラではなく、別のツールの仕事です。
たとえば、以下のコードは完全に問題ありません。
int *p = NULL;
int &r = *p;
これはNULL参照です。特にない。
これらは私の2セントです。