13

C++11 標準(5.17、expr.ass) は次のように述べています。

いずれの場合も、代入は、右オペランドと左オペランドの値の計算の後、代入式の値の計算の前に順序付けされます。不定順序の関数呼び出しに関しては、複合代入の操作は単一の評価です。

私が理解しているように、指定された割り当ての一部であるすべての式は、割り当て自体の前に評価されます。このルールは、同じ割り当てで同じ変数を 2 回変更した場合でも機能するはずです。これは、以前は未定義の動作であったことは確かです。

指定されたコードは次のようになります:

int a = 0;
a = (a+=1) = 10;

if ( a == 10 ) {
    printf("this is defined");
} else {
    printf("undefined"); 
}

常にa==10?に評価されます。

4

3 に答える 3

8

はい、C++98 と C++11 の間で変更がありました。あなたの例は、C++ 11 ルールの下で明確に定義されていると思いますが、C++ 98 ルールの下では未定義の動作を示します。

より簡単な例として、x = ++x;は C++98 では定義されていませんが、C++11 では明確に定義されています。はまだ定義されていないことに注意してくださいx = x++;(ポストインクリメントの副作用は式の評価でシーケンスされませんが、プレインクリメントの副作用は同じ前にシーケンスされます)。

于 2013-10-25T16:34:35.037 に答える
7

コードを次のように書き直しましょう。

E1 = (E2 = E3)

ここで、E1 は式a、E2 は式a += 1、E3 は式10です。ここでは、代入演算子が右から左にグループ化されることを使用しました (C++11 標準の§5.17/1)。

§5.17/1 はさらに次のように述べています。

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

これを式に適用すると、最初に部分式E1and を評価する必要がありE2 = E3ます。これらの 2 つの評価の間には "sequenced-before" 関係はありませんが、問題は発生しないことに注意してください。

id-expression の評価E1は自明です (結果はaそれ自体です)。代入式 の評価は次のE2 = E3ように進行します。

まず、両方の部分式を評価する必要があります。リテラル の評価もE3自明です (値 10 の prvalue を与えます)。

(複合)割り当て式 E2の評価は、次の手順で行われます。

1) の動作a += 1は同等ですがa = a + 1a一度しか評価されません (§5.17/7)。部分式aand を1(任意の順序で)評価した後、に格納されている値を読み取るために、左辺値から右辺値への変換が に適用されます。aa

2) の値a(これは0) との値1が加算され ( a + 1)、この加算の結果は value の prvalue です1

3) 割り当ての結果を計算する前にa = a + 1、左側のオペランドが参照するオブジェクトの値が右側のオペランドの値に置き換えられます (§5.17/2)。の結果はE2、新しい値を参照する左辺値1です。副作用 (左側のオペランドの値の更新) は、代入式の値計算の前に並べられることに注意してください。これは上記の§5.17/1 です。

部分式E2とを評価したのでE3、式が参照する値は の値でE2置き換えられます。したがって、 の結果はvalue の左辺値です。E310E2 = E310

最後に、式E1が参照する値は式の値に置き換えられ、式E2 = E3は と計算されます10。したがって、変数aには値が含まれることになります10

これらのステップはすべて明確に定義されているため、式全体から明確に定義された値が得られます。

于 2013-10-30T12:54:25.620 に答える
4

少し調査した結果、コードの動作は C++11 で明確に定義されていると確信しました。

$1.9/15 州:

演算子のオペランドの値の計算は、演算子の結果の値の計算の前に並べられます。

$5.17/1 の状態:

代入演算子 ( =) と複合代入演算子はすべて右から左にグループ化されます。

私が正しく理解していれば、あなたの例では

a = (a+=1) = 10;

これは、 と の値の計算は、 の値の計算の前に実行する必要があり、この式の値の計算は、 が評価される前に終了する必要があることを意味し(a+=1)ます。 10(a+=1) = 10a = (a+=1) = 10;

$5.17/1 の状態:

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

これは、代入が値計算の前に行われなければならないことを意味します。したがって、推移性により、 の評価は(a+=1) = 10代入後にのみ開始できますa+=1(その値は、副作用の後にのみ計算される可能性があるため)。

2 番目と 3 番目の割り当てについても同じことが言えます。

この優れた回答も参照してください。これは、sequenced-before 関係を私よりもはるかに詳細に説明しています。

于 2013-10-29T22:34:32.830 に答える