为什么 cout<<++i + ar[++i];和 cout<<ar[++i]+ ++i;给出不同的输出?

Why cout<<++i + ar[++i]; and cout<<ar[++i]+ ++i; give different output?

我已阅读有关未定义行为的内容。

a[i] = a[i++] 导致未定义的行为。

但是我不明白为什么

的输出
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
cout << arr[++i] + ++i << " " << i;

3 2

的输出
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i = 0;
cout << ++i + arr[++i] << " " << i;

4 2

首先 - a[i] = a[i++] 自 C++17 以来定义明确。在该标准修订版中,顺序规则大大收紧,赋值运算符右侧的求值 顺序在 左侧的求值之前,这意味着所有右侧的副作用必须在左侧的评估开始之前完成。

所以该代码等同于a[i+1] = a[i]; ++i;


自 C++17 起,<< 运算符也具有左右排序,即左操作数右操作数之前排序。

现在,++i 定义为 i+=1,并且与上述类似的考虑适用于复合赋值运算符的计算。我们可以说 ++i 是“原子地”发生的。

但是,+ 运算符仍然是 未排序的 ,这是由 [intro.execution]/17:

定义的

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

[...]

If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined

不幸的是,这意味着 ++i + a[++i] 的行为仍然未定义,因为 + 的左操作数修改 i,而 + 的右操作数修改 i,并且这些操作数计算相对于彼此是无序的。


之前有人提议让 + 和类似的运算符也按左右顺序排列,但显然这还没有被标准接受。