以下内容是否完全定义:
int x = 42, y = x;
即严格等同于:
int x = 42;
int y = x;
编辑:问题不是关于风格(我知道这是错误的...),问题是“理论上的”
以下内容是否完全定义:
int x = 42, y = x;
即严格等同于:
int x = 42;
int y = x;
编辑:问题不是关于风格(我知道这是错误的...),问题是“理论上的”
正确答案是
int x = 42, y = x;
和
int x = 42;
int y = x;
考虑标准§ 8声明符[dcl.decl]:
3
每个声明中的初始化声明符都被单独分析,就好像它在一个声明中。
并且脚注[100]进一步解释:
具有多个声明符的声明通常等效于相应的具有单个声明符的声明序列。也就是说
T D1,D2,... Dn;
通常相当于
T D1; T D2; ... T Dn;
其中T是一个decl-specifier-seq,而每个Di都是一个init-declarator。
以上保证x = 42
和y = x
会单独进行评估。但是,正如@Praetorian在评论中正确指出的那样,脚注并不具有规范性。
这意味着评估顺序没有定义,并且实现者也可以按相反的顺序实现声明的评估(即T Dn; ...T D2; T D1;
)。
有人可能会认为逗号运算符保证从左到右进行评估。然而,事实并非如此。根据K&R[K&R II,3.6 p.63]的说法,这也适用于C ++:
分隔函数参数、声明变量等的逗号不是逗号运算符,并且不保证从左到右进行评估。
y
有可能没有被初始化为 42
吗? - M.My = x, x = 42
不是一个有效的表达式。因此,在这种情况下,编译器会生成一个错误。 - 101010Yes
。在这个声明和定义中:
int a = 2, b = a;
是否保证b总是初始化为2?如果是,那么我们可以说a = 2总是在b = a之前进行分析(或评估)吗?
答案的相关部分是:是的。严格来说,程序的可观察行为必须是作为声明的'a = 2'部分的所有副作用在'b = a'部分的评估开始之前发生的。 (当然,在这个简单的例子中,编译器可以以任何顺序甚至并行地将2分配给a和b,因为这样做会导致相同的可观察行为。)
并且更进一步:但是,在这种特殊情况下,它确实将声明符列表分为单独的声明符;每个声明符都包含一个完整的表达式,并且按顺序评估声明符。
更新 每个init-declator成为一个full expression的原因很微妙,但据我所知,遵循了我在Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11中使用的相同逻辑。在这种情况下,我们从第8节中定义的语法开始:init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator initializeropt
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
int x = 42, y = x;
^ ^
| end full-expression
end full-expression
1.9
段第14款,我们可以看到:
至于评估顺序,我认为这没有明确规定,在初始化程序列表的缺陷报告430中适用于相同逻辑也将适用于此处。在C++11中,初始化程序列表的语言已通过在第与完整表达式相关的每个值计算和副作用都在下一个要评估的完整表达式相关的每个值计算和副作用之前被排序。8.
8.5.4
节中添加以下内容进行修复:
对于initializer,不存在这样的等效物。在大括号初始化列表的初始化程序列表中,包括任何由打包扩展(14.5.3)产生的初始化程序子句在内,按它们出现的顺序进行评估。[...]
x
的初始化既不是完整表达式 42
的一部分,也不是表达式的副作用,对吗? - dyp3.3.2 p1
节是否意味着顺序,我可以理解为它可能被读作那样。随后的段落也似乎暗示了一种顺序。 - Shafik Yaghmour