15

私はしばらくの間プログラムをデバッグしてきましたが、最終的にエラーは参照が更新されていないことが原因であることがわかりました。

私が遭遇した問題を示す例を次に示します。

#include <iostream>
using namespace std;

struct Test {
    Test& set(int& i){ i = 10; return *this; }
    Test& print(const int& i){ cout << i << endl; return *this; }
};

int main(void){
    int i = 0;
    Test t;

    t.set(i).print(i + 5);

    return 0;
}

ここでの print() メソッドは 15 を出力すると予想していましたが、代わりに 5 を出力します。

編集: 10 日後、clang を使用すると 15 が出力されることに気付きました! これは GCC のバグですか?

4

3 に答える 3

10

これについて C++11 標準を解釈してみましょう。§1.9/15 には次のように書かれています。

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

確かintに はスカラー型であり、inおよび値の計算t.set(i).print(i + 5);に副作用が含まれているため、特に明記されていない限り、動作は未定義です。§5.2.5 (「クラス メンバー アクセス」) を読んで、演算子に関するシーケンスに関するメモを見つけることができませんでした。[ただし、以下の編集を参照してください!]iset()i + 5.

ただし、後者は前者の戻り値を (暗黙の) 引数として受け取るため、set()が前に実行されることはもちろん保証されます。ここでの犯人は、の引数の値の計算がprint()thisprint順不同の呼び出しに対して不定に順序付けられますset

編集:あなたの(@Xenoの)コメントで答えを読んだ後、標準の段落を読み直しましたが、実際には後で次のように述べています:

呼び出された関数の本体の実行の前または後に特に順序付けされていない呼び出し側関数 (他の関数呼び出しを含む) 内のすべての評価は、呼び出された関数の実行に関して不定に順序付けられます。

indeterminately sequencedはunsequencedではないため(「unsequenced 評価の実行は重複する可能性がある」、§1.9/13)、これは実際には未定義の動作ではなく、「単なる」未指定の動作であり、15 と 5 の両方が正しい出力であることを意味します。

したがって、 when<は「前に配列された」を~意味し、「不確定に配列された」を意味します。

(value computations for print()'s arguments ~ execution of set()) < execution of print()

于 2014-02-16T13:09:36.663 に答える
0

[コメントするには長すぎます:]

追加する場合

Test& add(int& i, const int toadd)
{
  i += toadd;
  return *this;
}

この呼び出し

t.set(i).add(i, 5).print(i);

戻り値

15

i + 5このことから、犯人は印刷する as パラメータであると結論付け ます。

于 2014-02-16T13:17:42.413 に答える