5

新学期を迎えました。
なぜ++ i ++期待どおりに機能しないのかという標準的な質問を受け取り始めました。

これらのタイプの質問の 1 つに答えただけで、新しい C++11 標準が変更され、これは未定義の動作ではなくなったと言われました。がandsequence pointsに置き換えられたと聞いたことがありますが、この件について深く (またはまったく) 読んでいません。sequenced beforesequenced after

だから私がちょうど答えていた質問は次のとおりでした:

int i = 12;
k = ++ (++ i);

質問は次のとおりです。

C++11 でシーケンス ポイントがどのように変更され、上記のような質問にどのように影響しますか。まだ定義されていない動作ですか、それとも明確に定義されていますか?

4

2 に答える 2

6

その場合の UB は [intro.execution]/15 に基づいています。

特に明記されていない限り、個々の演算子のオペランドおよび個々の式の部分式の評価は順不同です。[...] 演算子のオペランドの値の計算は、演算子の結果の値の計算の前に並べられます。スカラー オブジェクトに対する副作用が、同じスカラー オブジェクトに対する別の副作用、または同じスカラー オブジェクトの値を使用した値の計算に対して順序付けされていない場合、動作は未定義です。

For ++(++i): [expr.pre.incr]/1 は++iとして定義されていi+=1ます。これは [expr.ass]/1 につながります。

いずれの場合も、代入は、右オペランドと左オペランドの値の計算の後、代入式の値の計算の前に順序付けされます。

したがって、++(++i)と同等(i+=1)+=1の の場合、内側の代入は外側の代入の前に並べられ、UB はありません。


[intro.execution]/15 には UB の例があります。

i = i++ + 1; // the behavior is undefined

ここでのケースは少し異なります (ここで前置/後置の間違いを指摘してくれたOktalistに感謝します)。[expr.post.incr]/1 は、後置インクリメントの効果を記述します。それは述べています:

式の値の計算は++、オペランド オブジェクトの変更の前に順序付けられます。

ただし、副作用(の変更)の順序付けに関する要件はありませんi。このような要件は、代入式によって課されることもあります。ただし、代入式では、代入の前にオペランドの値の計算のみが必要です(副作用は必要ありません)。i = ..したがって、とを介した 2 つの変更はシーケンス化i++されておらず、未定義の動作が発生します。

NBには同じ問題i = (i = 1);はありませi = 1。内部代入は、同じ式の値計算の前に順序付けされるという副作用を保証します。また、値は外部代入に必要です。これにより、それ (右側のオペランドの値の計算(i = 1)) が外部代入の副作用の前に順序付けられることが保証されます。同様に、i = ++i + 1;(と同等i = (i+=1) + 1;) には動作が定義されています。


コンマ演算子は、副作用が順序付けられる例です。[expr.comma]/1

左の式に関連付けられたすべての値の計算と副作用は、右の式に関連付けられたすべての値の計算と副作用の前に並べられます。

[intro.execution]/15 には例i = 7, i++, i++;(読み取り: ) が含まれており、これは(i=7), i++, i++;定義済みの動作 ( become ) です。i9

于 2013-09-28T17:55:45.313 に答える
3

シーケンスはあなたの状況には関係ないと思います。式++i++は としてグループ化される++(i++)ため、次のようになります。

  • iが組み込み型の場合、i++は右辺値であるため、これは無効です。

  • iがユーザー定義型で、演算子がオーバーロードされている場合、これは などのネストされた関数呼び出しでありT::operator++(T::operator++(i), 0)、関数呼び出しが評価される前に関数引数が評価されます。

于 2013-09-28T17:46:01.423 に答える