int a = ++i + ++i 是未定义的行为吗?

Is int a = ++i + ++i undefined behaviour?

考虑以下代码:

int main(){
  int i = 0;
  int a = ++i + ++i;
}

我找不到任何信息说 + 的操作数是无序的。所以根据标准,二进制+的操作数序列是不确定的。

[intro,excution]/15

Given any two evaluations A and B, if A is sequenced before B (or, equivalently, B is sequenced after A), then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap.  — end note ]

Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.[ Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first.  — end note ]

引号表示 A 的求值可以发生在 B 之前,或者 B 的求值可以发生在 A 之前。并且执行未排序的计算 可以重叠 ,而不确定排序的计算不能重叠,两者不同

我们知道 i 的修改总是发生在 i 的值计算之前,因为前缀 ++.

那么按照规则:

Evaluation of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects

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

因此,无论 A 的评估在 B 之前还是相反,都没有与相应值计算相关的副作用或 ++i + ++i; 的副作用。因为不确定顺序的评估不能重叠,所以两个评估之一必须在另一个评估之前完全执行。评估包括价值计算和副作用。因此,i 的一个增量先于另一个计算。

然而,未排序的计算遵循不同的规则,因此如果对二进制 + 的操作数的计算是 未排序的 而不是不确定排序的,则混淆将得到解决。如果我在上面的分析中遗漏了标准中的某些内容,请指正。

更新

我发现了下面这句话,这句话似乎在暗示求值是无序的:

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

但是,我不知道如何正确理解这句话。我想出了两种解释:

For an operator A, the evaluations of the operands of A are unsequenced with each other; for an expression B, the evaluations of the subexpressions of B are unsequenced with each other.

Take evaluations of operands of individual operators as A. Take evaluations of subexpressions of individual expressions as B. A is unsequenced with B.

哪种解释是正确的?

标准文本似乎1 暗示行为未定义。

  • <a>+<b><a><b> 的计算未排序2,3
  • 这两个部分有影响相同内存位置的副作用

(1) 这部分在我看来是明确和明确的,但我不确定是否有其他部分在说相反的或更高层次的概念(例如什么是程序的执行)并没有因为规则矛盾而在逻辑上被破坏。考虑到 C++ 的复杂性,如果没有出现错误,我会感到非常惊讶。

(2) 在重载的情况下 operator+ 它们将被不确定地排序(因为规则与函数调用相同,因此不是未定义的行为:N4713 的 8.5.1.2[5] 说“后缀表达式在表达式列表中的每个表达式和任何默认参数之前排序。参数的初始化,包括每个关联值计算和副作用,是不确定的 相对于任何其他参数的排序”)但对于本机 ints 这不适用并且行为未定义。

(3) 文字说 "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced"。当然,对于一元运算符来说,这个问题是无关紧要的(没有顺序可谈),对于三元运算符 ?: 来说,有特殊的排序规则。关于 "subexpressions" 的部分是为了涵盖像 a[++i][++i] 这样的情况,其中 a 例如是 char **:在这种情况下,两个相同的子表达式 ++i 是未排序的并且副作用会修改相同的内存位置,从而导致未定义的行为。我认为该段落实际上比必要的更复杂,因为运算符的操作数也是表达式的子表达式,因此最后一部分就足够了。

让我给出一个答案,让问题的答案更清晰。 首先,考虑下面的句子

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

句子可以拆分成两个

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

那么,1部分是什么意思?意思是一个集合X由一个运算符的这些操作数组成,集合X中的每个元素都是无序的,它们是unsequenced.The 句子 2 和句子 1 类似,只是让集合 X 由一个表达式的这些子表达式组成。

二元运算符 + 的那些语句在 [expr.additive] 中进行了描述,这些与该部分中的操作数序列无关,因此,对 [= 执行的规则 1 34=],正如标准所说的无序可以重叠,这是什么意思?这意味着"the parts of each evaluation can even be interleaved together"(@Ben Voigt在评论中说)。因此,对于++i + ++i,它通常是这样的:

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

所以,int a = ++i + ++i是undefined behavior,这道题的重点是理解下面这句话:

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