"读取"POD预增量结果不会产生未定义的行为.为什么呢?

mlv*_*ljr 7 c c++ standards language-lawyer

这是一个愚蠢的问题.:)

[编辑:愚蠢与否,这结果是一个C++特殊问题,请参阅UPDATE_2]

假设我们有:

int a = 0; // line 1
int b = ++a; // line 2
Run Code Online (Sandbox Code Playgroud)

第2行发生的事情是(注意,数字只是标记,不指定确切的顺序):

                      = [1: write result of (3) to result of (2)]
                     /\
[2: take "b" l-value] [3: convert result of (4) to an r-value ]
                      |
                      [4: take "a" l-value, "increment" and return it]
Run Code Online (Sandbox Code Playgroud)

(4)中的"写入"在(3)中的"读取"之前是"有序"的,并且由于之间没有序列点,所以不能保证在(3)之前发生副作用(还有"读"inside(4)本身,但 "write" 之前订购,这样就不会产生UB).

那么,上面的错误在哪里?

[更新,针对没有经验丰富的序列点律师:)]

换句话说,问题是:

  1. 似乎存在"竞争"是否首先发生l值到r值转换("读取")或增量("写入")副作用.

  2. 在C中,根据JTC1/SC22/WG14 N926"序列点分析"*,将给出UB(参见,例如,实施例5 :)int x,y; (x=y) + x; // UB.

  3. 注意,这不会是一个的情况下应后增由于被使用(3)和(4)将构成一个单一的 [(3):以"A" L值,将其转换为r值,并返回该r值] 与"写"副作用延迟到下一个序列点之前的某个地方

_

(*)这看起来是C99标准委员会成员给出的最干净的系统理论基础.

[UPDATE_2]

  1. 获得的经验教训:永远不要用C规则判断C++ :)).我确实想知道为什么N926(它干净地描述了C99的方式)对于预增量产生l值的话题"不够清楚".

  2. 问题出现了,如何为C++建立一个类似的基本原理,因为没有一个,因为即使在C情况下,只是解释标准是相当困难的,而且C++语言标准更加复杂和模糊.

[UPDATE_3]

"共同表达的不确定性"中讨论了一些相关主题(至少在〜新的一半).加上该事项由委员会讨论的人在这里(参见"222序列点和左值返回运营商").

Joh*_*itb 2

我想解决办法可能就是“++i”的写法。它说“该值是操作数的新值;它是一个左值。”。并且行为在 5/4 中未定义为“此外,仅应访问先前值以确定要存储的值。”。

因此,我们访问的不是先前的值,而是新的值。然后我们可能就没事了。不过,未定义行为和已定义行为之间似乎只有一线之隔。

实际上,“先前值”对我来说听起来就像“对象在前一个序列点具有的值”。如果这样解释,那么这个构造看起来是未定义的。但如果我们直接比较 5.3/2 和 5/4 中“++i”的措辞,我们就会面临“新值”与“先前值”,并且事物会“弯曲”到定义的行为(“++i” " 将在下一个序列点查看“i”的值,并生成该值作为“++i”的结果左值的内容)。