5

次のコードを検討してください。

int main()
{
    int count = 0 ;
    int arrInt[2] = { count++, count++ } ;

    return 0 ;
}

それを使用してコードをコンパイルするclang -std=c++03と、次の警告が生成されます ( live example ):

warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
    int arrInt[2] = { count++, count++ } ;
                           ^        ~~

私はこのようなコードを推奨しているわけではありませんが、同様のコードが別の質問で出てきて、C++11より前の標準に従って定義されているかどうかについて意見の相違がありました。C++ 11 では、この動作はAre multiple Mutation within initializer lists undefined behaviorに従って明確に定義された動作であり、実際に使用すると警告が消えます。-std=c++11

C++11より前の ドラフト標準を見ると、initializer-listをカバーする同じ言語がないため、Chapter 5 のパラグラフ4が残っているようです。

特に明記されていない限り、個々の演算子のオペランドと個々の式の部分式の評価の順序、および副作用が発生する順序は規定されていません。57)前のシーケンス ポイントと次のシーケンス ポイントの間で、スカラー オブジェクトは、式の評価によって最大 1 回変更された格納された値を持たなければなりません。さらに、保存する値を決定するためにのみ、前の値にアクセスする必要があります。この段落の要件は、完全な式の部分式の許容される順序ごとに満たされるものとします。それ以外の場合、動作は未定義です。

これを未定義にするためには、として、したがってそれぞれを部分式count++, count++として解釈する必要があるように思われるので、このコードはC++11より前に未定義ですか?count++

4

1 に答える 1

4

コードはC++11より前では未定義ではありませんが、評価順序は未指定です。草案の標準セクションを見ると、プログラムの実行の段落12には次のように書かれています。1.9

完全式は、別の式の部分式ではない式です。[...]

そしてパラグラフ15は言う:

各完全式の評価が完了すると、シーケンスポイントがあります12)

問題はcount++, count++完全な式でそれぞれcount++部分式であるか、またはそれぞれcount++が独自の完全な式であり、したがってそれぞれの後にシーケンス ポイントがあるかということです。8.5 セクションInitializersからこの初期化の文法を見ると:

initializer-clause:
  assignment-expression
  { initializer-list ,opt }
  { }
initializer-list:
  initializer-clause
  initializer-list , initializer-clause

私たちが持っている唯一の式は代入式であり,、コンポーネントの分離は式の一部ではなく初期化子リストの一部であるため、それぞれが完全な式あり、それぞれの後にシーケンスポイントがあります。count++

この解釈は、私のものと非常によく似たコードを持つ次のgcc バグ レポートによって確認されています (このバグ レポートを見つける前に、私の例を思いつきました)。

int count = 23;
int foo[] = { count++, count++, count++ };

これは、欠陥レポート 430になります。これを引用します。

[...]上記の各イニシャライザ式は完全な式 (1.9 [intro.execution]/12-13; issue 392 も参照) であり、したがって各式の後にシーケンス ポイントがあることが標準で明確になっていると思います。 (1.9 [intro.execution]/16)。私は、標準が式が評価される順序を決定していないように見えることに同意します。おそらくそうすべきです。式を左から右に評価しないコンパイラを知っている人はいますか?

于 2013-11-09T18:59:54.483 に答える