なぜf(i = -1、i = -1)が未定義の動作なのですか?
私は評価違反の順序について読んでいて、私を困惑させる例を示しています。 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, …