17

このトピックをもう一度開いて申し訳ありませんが、このトピック自体について考えると、未定義動作が発生し始めました。明確に定義された動作のゾーンに移動したい。

与えられた

int i = 0;
int v[10];
i = ++i;     //Expr1
i = i++;     //Expr2
++ ++i;      //Expr3
i = v[i++];  //Expr4

上記の表現を(この順序で)次のように考えます

operator=(i, operator++(i))    ; //Expr1 equivalent
operator=(i, operator++(i, 0)) ; //Expr2 equivalent
operator++(operator++(i))      ; //Expr3 equivalent
operator=(i, operator[](operator++(i, 0)); //Expr4 equivalent

ここでの動作については、 C++0xからの重要な引用です。

$ 1.9 / 12-「式(または部分式)の評価には、一般に、値の計算(左辺値評価のためのオブジェクトのIDの決定と、右辺値評価のためにオブジェクトに以前に割り当てられた値のフェッチを含む)と副作用の開始の両方が含まれます。 。」

$ 1.9 / 15-「スカラーオブジェクトの副作用が、同じスカラーオブジェクトの別の副作用、または同じスカラーオブジェクトの値を使用した値の計算に比べて順序付けされていない場合、動作は定義されていません。」

[注:異なる引数式に関連する値の計算と副作用は順序付けられていません。—エンドノート]

$ 3.9 / 9-「算術型(3.9.1)、列挙型、ポインター型、メンバー型へのポインター(3.9.2)、std :: nullptr_t、およびこれらの型のcv修飾バージョン(3.9.3)はまとめて呼び出されますスカラー型。」

  • Expr1では、式i(最初の引数)の評価は、式(副作用があります)の評価に関して順序付けられていませんoperator++(i)

    したがって、Expr1の動作は未定義です。

  • Expr2では、式i(最初の引数)の評価は、operator++(i, 0)(副作用がある)式の評価に関して順序付けられていません。

    したがって、Expr2の動作は未定義です。

  • Expr3では、 outerが呼び出されるoperator++(i)前に、lone引数の評価を完了する必要があります。operator++

    したがって、Expr3の動作は明確に定義されています。

  • Expr4では、式i(最初の引数)の評価は、operator[](operator++(i, 0)(副作用があります)の評価に関して順序付けられていません。

    したがって、Expr4の動作は未定義です。

この理解は正しいですか?


PSOPのように式を分析する方法が正しくありません。これは、@ Potatoswatterのように、次のように述べているためです。「13.6節は適用されません。13.6/ 1の免責事項を参照してください。」これらの候補関数は、13.3.1.2で説明されている演算子のオーバーロード解決プロセスに参加し、他の目的には使用されません。 「これらは単なるダミーの宣言です。組み込み演算子に関しては、関数呼び出しのセマンティクスは存在しません。」

4

2 に答える 2

15

ネイティブ演算子式は、オーバーロードされた演算子式と同等ではありません。関数の引数への値のバインドにはシーケンスポイントがあり、operator++()バージョンが明確に定義されます。しかし、それはネイティブタイプの場合には存在しません。

4つのケースすべてiで、完全な式内で2回変更されます。,式に、、、||またはが表示されないため、これは&&インスタントUBです。

§5/4:

前のシーケンスポイントと次のシーケンスポイントの間で、スカラーオブジェクトは、式の評価によって、格納されている値を最大で1回変更する必要があります。

C ++ 0x用に編集(更新)

§1.9/15:

演算子のオペランドの値の計算は、演算子の結果の値の計算の前に順序付けられます。スカラーオブジェクトの副作用が、同じスカラーオブジェクトの別の副作用、または同じスカラーオブジェクトの値を使用した値の計算に比べて順序付けされていない場合、動作は定義されていません。

ただし、値の計算と副作用は2つの異なるものであることに注意してください。++iがと同等である場合i = i+1+は値の計算であり、=は副作用です。1.9 / 12から:

式(または部分式)の評価には、一般に、値の計算(glvalue評価のためにオブジェクトのIDを決定し、prvalue評価のためにオブジェクトに以前に割り当てられた値をフェッチすることを含む)と副作用の開始の両方が含まれます。

したがって、値の計算はC++03よりもC++0xでより強力にシーケンスされますが、副作用はそうではありません。同じ式の2つの副作用は、特に順序付けされていない限り、UBを生成します。

値の計算はとにかくデータの依存関係によって順序付けられ、副作用がない場合、評価の順序は観察できないため、C ++ 0xが何かを言うのに苦労する理由はわかりませんが、それは私がもっと読む必要があることを意味しますベームとその友人たちによる論文の

編集#3:

PDFリーダーの検索バーに「シーケンス」と入力する怠惰に対処してくれたJohannesに感謝します。私はとにかく寝て最後の2つの編集で起きようとしていました…そうです;v)。

代入演算子を定義する§5.17/1は言う

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

また、プリインクリメント演算子の§5.3.2/1は次のように述べています

xがbool型でない場合、式++xはx+ = 1と同等です[注:…加算(5.7)および代入演算子(5.17)…を参照]。

このアイデンティティにより、++ ++ xはの省略形です(x +=1) +=1。それで、それを解釈しましょう。

  • 遠いRHSで評価1し、parensに降ります。
  • の内部1と値(prvalue)およびアドレス(glvalue)を評価しxます。
  • ここで、+=部分式の値が必要です。
    • その部分式の値の計算は完了です。
    • 割り当ての値が使用可能になる前に、割り当ての副作用を順序付ける必要があります。
  • 新しい値をに割り当てますx。これは、部分式のglvalueおよびprvalueの結果と同じです。
  • 私たちは今森の外にいます。これで、式全体がに縮小されましたx +=1

したがって、 1と3は明確に定義されており、2と4は未定義の動作です。

N3126で「sequenced」を検索して見つけた他の唯一の驚きは5.3.4/16でした。ここでは、operator newコンストラクター引数を評価する前に実装を呼び出すことができます。カッコいい。

編集#4 :(ああ、私たちが織り成すもつれたウェブ)

Johannesはi == ++i;、のglvalue(別名アドレス)が。iにあいまいに依存していることを再度指摘し++iます。glvalueは確かにの値ですがi、1.9 / 15は、名前付きオブジェクトのglvalueが一定であり、実際には依存関係を持つことができないという単純な理由から、それを含めることを意図しているとは思いません。

有益なストローマンについては、検討してください

( i % 2? i : j ) = ++ i; // certainly undefined

ここで、のLHSのglvalueは、のprvalueの=副作用に依存しiます。のアドレスは問題でiはありません。の結果は?:です。

おそらく良い反例は

int i = 3, &j = i;
j = ++ i;

ここjに、とは異なる(ただし同一の)glvalueがありiます。これは明確に定義されていますが、そうでi = ++iはありませんか?これは、コンパイラーがどのような場合にも適用できる簡単な変換を表しています。

1.9/15は言うべきです

スカラーオブジェクトの副作用が、同じスカラーオブジェクトの別の副作用、または同じスカラーオブジェクトのprvalueを使用した値の計算に比べて順序付けされていない場合、動作は定義されていません。

于 2010-10-04T04:09:27.580 に答える
0

上記のような表現を考えると、メモリにインターロックがあり、読み取り-変更-書き込みシーケンスの一部としてメモリ位置を読み取ると、の最終書き込み以外の読み取りまたは書き込みが試行されるマシンを想像すると便利です。シーケンス。シーケンスが完了するまでストールします。そのようなマシンは、ばかげた概念ではありません。実際、このような設計は、多くのマルチスレッドコードシナリオを単純化する可能性があります。一方、「x =y++;」のような式 'x'と'y'が同じ変数への参照であり、コンパイラーが生成したコードがread-and-lock reg1 = yのようなことをした場合、そのようなマシンで失敗する可能性があります。reg2 = reg1 + 1; x=reg1と書く; 書き込みとロック解除y=reg2。

于 2011-11-01T14:55:31.007 に答える