次のコードは、g++ と Visual C++ の両方でコンパイルに合格できます。なぜ合法なのですか?これは理不尽に見え、隠れたバグを引き起こす可能性があります。
int main() {
int i = i;
}
次のコードは、g++ と Visual C++ の両方でコンパイルに合格できます。なぜ合法なのですか?これは理不尽に見え、隠れたバグを引き起こす可能性があります。
int main() {
int i = i;
}
編集:構文的には正当ですが、 を使用すると未定義の動作が発生しますx
。
初期化されていない変数を別の(まあ、同じ)初期化されていない変数に割り当てているため、これは合法ではありません。コンパイルできるからといって、合法であるとは限りません。はい、有効な C++ 構文ですが、合法ではありません。
代入演算子の右辺は、代入時に完全に評価する必要があります。この場合、i
初期化されていない です。
引用を掘り下げたSteve Jessopの功績:
4.1/1、左辺値から右辺値への変換
[...] オブジェクトが初期化されていない場合、この変換を必要とするプログラムの動作は未定義です。
構文で許可されている理由は、独自の初期化子でポインターまたは参照によって変数を使用したい場合があるという奇妙なケースがあるためです。
struct ThingManager {
void *thing;
ThingManager(void *thing) : thing(thing) {}
void Speak() {
if (thing == (void*)this) {
std::cout << "I'm managing myself\n";
} else {
std::cout << "I'm managing " << thing << "\n";
}
}
};
ThingManager self_manager(&self_manager);
ThingManager other_manager(&self_manager);
したがって、C ++では、独自の初期化式でオブジェクトを参照できます(その名前はスコープ内にあります)。次に、C ++の場合と同様に、初期化されていない値を実際に使用しないようにするのは問題です(たとえば、int i = i;
初期化されていない値を使用します)。
コンパイラは、初期化されていない値の使用を識別するのに役立つ場合がありますが、標準では必要ありません。
以前に宣言された変数を、別の変数の初期化子として使用できます。
この場合、コンパイラは解析するとすぐにint i
それをシンボル テーブルに追加するため、= i
初期化子を確認すると、シンボルは前の宣言から解決できます。
意味的に疑わしい場合でも、ソースコードが指定することを明確に正確に実行するコードを生成できるという点で、コンパイラはそれを理解できるため、エラーではありません。C および C++ の哲学は、構文的にコンパイルできるものはすべてコンパイルすることです。セマンティック エラーは通常、警告のみを発行し、そのような警告が有効になっている場合にのみ発行します。