C ++ 20標準草案の[basic.scope.pdecl] / 1には、次の(非規範的)例が注記(プルリクエスト3580のマージ前の部分的な引用、この質問への回答を参照)に含まれていました。
unsigned char x = x;
[...] xは、独自の(不定)値で初期化されます。
これは実際にC ++ 20で明確に定義された動作を持っていますか?
一般に、フォームの自己初期化は、初期化が完了する前のの値が不定であるT x = x;
ため、未定義の動作をします。不確定な値を評価すると、通常、未定義の動作([basic.indent] / 2)が発生しますが、[basic.indent] /2.3には、不確定な値を持つ左辺値から変数を直接初期化できる特定の例外があります(不確定な値で初期化が発生します) )。x
unsigned char
unsigned char
これだけでは、したがって、未定義の動作を引き起こすが、他のタイプの場合としないT
符号なしの狭い文字タイプかそうでないstd::byte
、例えばint x = x;
。C ++ 17以前にも適用されたこれらの考慮事項は、下部にあるリンクされた質問も参照してください。
ただし、でもunsigned char x = x;
、現在のドラフトの[basic.lifetime] / 7は次のように述べています。
同様に、オブジェクトの存続期間が始まる前に[...]その値に依存しないglvalueのプロパティを使用することは明確に定義されています。次の場合、プログラムは未定義の動作をします。
glvalueは、オブジェクトにアクセスするために使用されます。
[...]
これはx
、例のの値がその存続期間中にのみ使用できることを意味するようです。
[...]
タイプTのオブジェクトの存続期間は、次の場合に始まります。
- [...]と
- 初期化(存在する場合)が完了している(空の初期化を含む)([dcl.init])、
[...]
したがって、x
の有効期間は、初期化が完了した後にのみ開始されます。ただし、引用された例では、の初期化が完了するx
前にの値が使用されていx
ます。したがって、使用には未定義の動作があります。
私の分析は正しいですか?正しい場合、次のような初期化前の使用の同様のケースに影響しますか?
int x = (x = 1);
私の知る限り、C ++ 17以前でも明確に定義されていたものはどれですか。
C ++ 17(最終ドラフト)では、ライフタイムを開始するための2番目の要件が異なっていたことに注意してください。
- オブジェクトに空でない初期化がある場合、その初期化は完了しています。
以来、x
C ++ 17の定義(ただし、現在のドラフト内の1つ)によって空虚初期化しなければならず、それは上記の例に初期にアクセスされたとき、その寿命は既に始まっていることになるので、両方の例ではない未定義の動作は存在しませんでしたx
C ++ 17の寿命のため。
C ++ 17以前の表現は再び異なりますが、結果は同じです。
問題は、不確定な値を使用する場合の未定義の動作に関するものではありません。これは、たとえば次の質問でカバーされています。
int x ^= x;
は構文的に整形式ではありません。イニシャライザを使用した変数定義(つまりint x = x;
、UBですが)またはxor割り当て式ステートメント(つまりx ^= x;
、x
タイプがの場合はUBですが、int
デフォルトで初期化され、事前に割り当てられていません)を使用できます。これら2つを1つに混在させることはできません。