私は評価違反の順序について読んでいて、私を困惑させる例を示しています。
1)スカラーオブジェクトの副作用が同じスカラーオブジェクトの別の副作用と比較してシーケンスされていない場合、動作は未定義です。
// snip f(i = -1, i = -1); // undefined behavior
このコンテキストでi
は、は明らかにスカラーオブジェクトです。
算術型(3.9.1)、列挙型、ポインター型、メンバー型へのポインター(3.9.2)、std :: nullptr_t、およびこれらの型のcv修飾バージョン(3.9.3)は、まとめてスカラー型と呼ばれます。
その場合、ステートメントがどのようにあいまいであるかはわかりません。最初または2番目の引数が最初に評価されるかどうかに関係なく、i
最終的に-1
、および両方の引数もであるように思え-1
ます。
誰かが明確にしてもらえますか?
更新
私はすべての議論に本当に感謝しています。これまでのところ、@ harmicの回答は非常に気に入っています。一見しただけではわかりやすいにもかかわらず、このステートメントを定義する際の落とし穴と複雑さを明らかにしているからです。@ acheong87は、参照を使用するときに発生するいくつかの問題を指摘していますが、これは、この質問のシーケンスされていない副作用の側面とは直交していると思います。
概要
この質問はかなりの注目を集めたので、主なポイント/回答を要約します。まず、少し補足して、「なぜ」は密接に関連しているが微妙に異なる意味を持つ可能性があることを指摘します。つまり、「原因」、「理由」、および「目的」です。私は、答えが「なぜ」のそれらの意味のどれに対処したかによってグループ分けします。
何のために
ここでの主な答えは、Paul Draperからのもので、Martin Jが同様の貢献をしましたが、それほど広くはありません。ポール・ドレイパーの答えは要約されます
動作が定義されていないため、未定義の動作です。
答えは、C ++標準の内容を説明するという点で、全体的に非常に優れています。また、f(++i, ++i);
やなど、UBのいくつかの関連するケースも扱いますf(i=1, i=-1);
。関連する最初のケースでは、最初の引数が必要かどうかi+1
、2番目の引数が必要かどうか、i+2
またはその逆が明確ではありません。2番目でi
は、関数呼び出しの後に1か-1 かが明確ではありません。これらのケースはどちらも次のルールに該当するため、UBです。
スカラーオブジェクトの副作用が同じスカラーオブジェクトの別の副作用と比較してシーケンスされていない場合、動作は未定義です。
したがって、f(i=-1, i=-1)
プログラマの意図が(IMHO)明白で明確であるにもかかわらず、同じ規則に該当するため、UBもです。
ポール・ドレイパーはまた、彼の結論でそれを明確にしています
動作が定義されているのでしょうか?はい。定義されましたか?番号。
「どのような理由/目的がf(i=-1, i=-1)
未定義の動作として残されたのか?」
どのような理由/目的で
C ++標準にはいくつかの見落とし(多分不注意)がありますが、多くの省略は十分な理由があり、特定の目的を果たします。目的は「コンパイラライターの仕事を簡単にする」または「コードを高速にする」のいずれかであることが多いことは承知していますが、主に UBのままにする正当な理由があるかどうかを知りたいと思っていましたf(i=-1, i=-1)
。
harmicとsupercatは、UBの理由を提供する主な答えを提供します。Harmicは、見かけ上アトミックな割り当て操作を複数の機械語命令に分割する可能性のある最適化コンパイラーと、それらの命令をさらにインターリーブして最適な速度にする可能性があることを指摘しています。これはいくつかの非常に驚くべき結果につながる可能性があります:i
彼のシナリオでは-2になります!したがって、harmicは、操作がシーケンスされていない場合に、変数に同じ値を複数回割り当てると悪影響を与える可能性があることを示しています。
supercatは、本来あるf(i=-1, i=-1)
べき姿を実行しようとすることの落とし穴の関連説明を提供します。一部のアーキテクチャでは、同じメモリアドレスへの複数の同時書き込みに対して厳しい制限があると彼は指摘します。コンパイラは、ほど重要ではないものを扱う場合、これを把握するのに苦労する可能性がありf(i=-1, i=-1)
ます。
davidfは、harmicと非常によく似たインターリーブ命令の例も提供します。
harmic、supercat、davidfの例はそれぞれ多少工夫されていますが、これらを組み合わせても、f(i=-1, i=-1)
未定義の動作となる具体的な理由を提供するのに役立ちます。
ポール・ドレイパーの回答が「何のために」の部分をよりよく扱っていたとしても、それが理由のすべての意味に対処するのに最善の仕事をしたので、私はハーミックの回答を受け入れました。
他の答え
JohnBは、(単なるスカラーではなく)多重定義された代入演算子を検討すると、問題が発生する可能性があることを指摘しています。
f(i-1, i = -1)
または類似したものを意味しています。
std::nullptr_t
、およびこれらの型のcv修飾バージョン(3.9.3)は、まとめてスカラー型と呼ばれます。 」