"只有确定要存储的值才能访问先前值"是什么意思?

Laz*_*zer 5 c++ undefined-behavior

从Prasoon对"未定义的行为和序列点"的问题的回答,我不明白以下是什么意思

..只能访问先前值以确定要存储的值.

作为示例,引用以下内容在C++中拥有Undefined Behavior:

  1. a[i] = i++;
  2. int x = i + i++;

尽管有解释,但我不明白这一部分(我想我正确理解了答案的其余部分).


我不明白上面的代码示例有什么问题.我认为这些已经为编译器定义了明确的步骤,如下所示.

a[i] = i++;

  • a[i] = i;
  • i = i + 1;

int x = i + i++ ;

  • x = i + i;
  • i = i + 1;

我错过了什么?什么是"前一个值是唯一的访问,以确定要存储的值"是什么意思?

Kei*_*son 5

另请参阅这个问题和我的回答。我不会投票将其作为重复项关闭,因为您询问的是 C++ 而不是 C,但我相信这两种语言的问题都是相同的。

仅应访问先前值以确定要存储的值。

这看起来确实是一个奇怪的要求;为什么标准应该关心访问值的原因?当您意识到如果读取先前的值来确定要存储在同一对象中的值时,这会隐式地对两个操作强加顺序,因此读取必须在写入之前发生,这是有意义的。由于这种顺序,对同一对象的两次访问(一次读取和一次写入)是安全的。编译器无法以导致代码相互干扰的方式重新排列(优化)代码。

另一方面,在像这样的表达式中

a[i] = i++
Run Code Online (Sandbox Code Playgroud)

对 进行了三种访问i:在左侧读取以确定a要修改 的哪个元素,在右侧读取以确定要递增的值,以及将递增的值存储回 中的写入i。右侧的读取和写入是可以的(i++本身是安全的),但是左侧的读取和右侧的写入之间没有定义的顺序。因此,编译器可以自由地重新排列代码,以改变这些读写操作之间的关系,并且标准象征性地举手并让行为未定义,对可能的后果只字不提。

C11 和 C++11 都更改了该区域的措辞,明确了一些排序要求。“先验值”的措辞不再存在。引用 C++11 标准草案 1.9p15:

除非另有说明,否则各个运算符的操作数和各个表达式的子表达式的求值都是无序的。[...] 运算符操作数的值计算在运算符结果的值计算之前进行排序。如果标量对象上的副作用相对于同一标量对象上的另一个副作用或使用同一标量对象的值的值计算而言是无序的,则该行为是未定义的。