29

我已经看过其他类似的问题并阅读了有关它的缺陷。但我还是不明白。为什么i = ++i + 1在 C++11 中定义明确,i = i++ + 1但不是?标准是如何明确定义的?

通过我的工作,我有以下排序的前图(其中箭头表示排序前的关系,除非另有说明,否则一切都是值计算):

i = ++i + 1
     ^
     |
assignment (side effect on i)
 ^      ^
 |      |
☆i   ++i + 1
     ||    ^
    i+=1   |
     ^     1
     |
★assignment (side effect on i)
  ^      ^
  |      |
  i      1

i用黑星标记了副作用,用白星标记了值计算i。这些似乎彼此之间没有顺序(根据我的逻辑)。标准说:

如果标量对象的副作用相对于同一标量对象的另一个副作用或使用同一标量对象的值的值计算是未排序的,则行为未定义。

缺陷报告中的解释没有帮助我理解。左值到右值的转换与什么有什么关系?我做错了什么?

4

3 回答 3

22

...或使用相同标量对象的值进行值计算...

重要的部分在这里加粗。左侧不使用 的值i进行值计算。正在计算的是一个glvalue。只有在之后(sequenced after),对象的值才会被触摸和替换。

不幸的是,这是一个非常微妙的观点:)

于 2012-12-22T18:49:33.567 回答
16

好吧,这里的关键时刻是 的结果++i是一个lvalue。为了参与二进制+,必须通过左值到右值的转换将左值转换为右值。左值到右值的转换基本上是i从内存中读取变量的行为。

这意味着++i应该直接从 读取一样获得 的值i。这意味着从概念上讲,在二进制评估开始之前,新的(增加的)值i必须准备好(必须物理存储在 中) 。i+

这种额外的顺序是无意中定义了这种情况下的行为的原因。

在 C++03 中,没有严格要求++i直接从i. 甚至在它被i + 1物理+存储在实际的i. 尽管可以合理地声称即使在 C++03 中也隐含了该要求(并且 C++03 不承认其存在的事实是 C++03 的缺陷)


在 的情况下i++,结果是一个右值i由于它已经是一个右值,因此不涉及左值到右值的转换,并且在我们开始评估二进制文件之前绝对不需要存储它+

于 2012-12-22T18:50:37.247 回答
4

自从提出这个问题以来,我已经写了一篇关于使用图形可视化 C++ 评估序列的文章。这个问题与 的情况相同i = ++i,它具有以下先序图:

i = ++i 的先序图

红色节点代表对 的副作用i。蓝色节点表示使用 的值的评估i。这个表达式定义明确的原因是因为这些节点中没有一个是彼此不排序的。赋值左边的使用i使用 的值i所以不是问题。

我缺少的主要部分是“使用价值”的含义。如果运算符期望该操作数的纯右值表达式,则使用其操作数的值。在给对象命名的时候,是一个左值,这个左值要经过左值到右值的转换,可以看成是“读取对象的值”。赋值只需要左操作数的左值,这意味着它不使用它的值。

于 2015-01-27T14:39:12.673 回答