递增在初始化列表中使用两次的变量 - 未定义的行为?

Incrementing a variable used twice in an initializer list - undefined behavior?

编辑:尚未回答 - 链接的问题是关于普通的 r 值,初始化列表是一个单独的,如果相关的概念。

此语句是否定义明确,或者在初始化列表中对在列表中出现两次的变量使用前缀递增运算符,未定义行为?

struct T t = { i, ++i };

我对 ANSI C 最感兴趣,但了解 C and/or C++ 的其他版本是否不同也很有用。如果像下面这样的类似构造是合法的:

struct T t = { i, i++ };

struct T t = { ++i, ++i };

struct T t = { i++, ++i };

struct T t = { i++, i++ };

C++11 及更高版本

list initialization. According to the sequenced-before rules(C++11 起)的行为已明确定义:

10) In list-initialization, every value computation and side effect of a given initializer clause is sequenced before every value computation and side effect associated with any initializer clause that follows it in the brace-enclosed comma-separated list of initalizers.

所以对于struct T t = { i, ++i };,会先求i,再求++i,顺序是明确的。所有其他样本也都可以。

引自 C++ 标准,$8.6.4/4 列表初始化 [dcl.init.list]:

(强调我的)

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions ([temp.variadic]), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. — end note ]

C

在 C 中(不一定与 C++ 的答案相同),没有与初始化列表的组件关联的序列点。

C11 标准,ISO/IEC 9899:2011,在 §6.7.9 初始化:

节中说

¶19 The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; 151)

151) Any initializer for the subobject which is overridden and so not used to initialize that subobject might not be evaluated at all.

这听起来很有希望,但是……

¶23 The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.152)

152) In particular, the evaluation order need not be the same as the order of subobject initialization.

因此,(在 C 中)评估的顺序是不确定的,您不能依赖增量发生的时间(或者,在问题中的代码未说明的极端情况下,增量是否发生)。

在C99(ISO/IEC 9899:1999)中,节号为§6.7.8,但第19段和第23段内容基本相同,只是脚注编号不同

在 C90 (ISO/IEC 9899:1990) 中,该问题未明确解决。

C++

songyuanyao's 来看,C++11(及以后)中的规则与C11中的规则不同。这种事情强调了 C 和 C++ 语言的不同,并使得为用这两种语言标记的问题编写全面的答案变得极其困难。

密切相关的问题

除了初始值设定项之外,至少还有两个其他问题与副作用(例如 ++)相关。他们也应该阅读。第二个,尤其是 C++ 用户感兴趣的;第一个标记为 C 而不是 C++,因此与那些对 C 感兴趣的人最相关。

  • Why are these constructs (using ++) undefined behaviour?

  • Undefined behaviour and sequence points

πάντα ῥεῖ 在评论中指出了两者。

在 C11 中,所有这些初始化的行为都不是未定义的。见 6.7.9/23:

The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.

术语不确定序列定义如下(5.1.2.3):

Evaluations A and B are indeterminately sequenced when A is sequenced either before or after B, but it is unspecified which.

在 C99 中,所使用的语言并没有清楚地说明是相同的情况还是未定义的行为。在 C89 中根本没有提到这个问题,所以我们应该假设在 C89 中这些是未定义的。