那么为什么i = ++ i + 1在C++ 11中定义明确?

Jos*_*eld 29 c++ undefined-behavior language-lawyer c++11

我已经看到了其他类似的问题,并阅读了有关它的缺陷.但我仍然没有得到它.为什么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
Run Code Online (Sandbox Code Playgroud)

i用黑星标记了一个副作用,i用白星计算了一个值.这些似乎相互之间没有相应的顺序(根据我的逻辑).标准说:

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

缺陷报告中的解释并没有帮助我理解.左值到右值的转换与任何事情有什么关系?我弄错了什么?

Joh*_*itb 22

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

重要的部分是加粗的.左侧不使用i值计算值.正在计算的是glvalue.仅在之后(之后排序),触摸并替换对象的值.

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

  • @sftrabbit是的."价值计算"中的"价值"用于"价值"实际意味着什么的不同含义.我认为它更像是"结果计算".请注意,标准表示在1.9p12"...值计算(包括确定glvalue评估对象的标识并获取先前分配给对象以进行prvalue评估的值)". (2认同)

AnT*_*AnT 16

那么,关键时刻是结果++i左值.并且为了参与二进制+,必须通过左值到右值的转换将左值转换为右值.Lvalue-to-rvalue转换基本上是i从内存中读取变量的行为.

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

这种额外的排序是无意中使得在这种情况下定义的行为.

在C++ 03中,没有严格要求++i直接从中获取值i.新值可以预测/预先拟定为i + 1二进制的操作数,+甚至在物理存储在实际存储之前i.尽管可以合理地声称要求是隐含的,即使在C++ 03中(并且C++ 03不承认它的存在是C++ 03的缺陷)


如果是i++,结果是右值.因为它已经是一个rvalue,所以没有涉及左值到右值的转换,并且i在我们开始评估二进制文件之前绝对没有要求存储它+.