使用逗号进行相互依赖的初始化?

Vin*_*ent 11 c++ initialization undefined-behavior language-lawyer c++11

以下是完美定义的:

int x = 42, y = x;
Run Code Online (Sandbox Code Playgroud)

即严格等同于:

int x = 42;
int y = x;
Run Code Online (Sandbox Code Playgroud)

编辑:问题不是关于风格(我知道这是错误的......),问题是"理论上的"

101*_*010 9

正确的答案是

int x = 42, y = x;
Run Code Online (Sandbox Code Playgroud)

int x = 42;
int y = x;
Run Code Online (Sandbox Code Playgroud)

通常是等价的(不严格).


考虑标准的§8声明符[dcl.decl]:

3 声明中的每个init-declarator都会被单独分析,就好像它本身就在声明中一样.

并在脚注[100]中进一步解释:

具有多个声明符的声明通常等效于具有单个声明符的相应声明序列.那是

T D1,D2,... Dn;

通常相当于

T D1; T D2; ...... T Dn;

其中T是decl-speci-er-seq,每个Di都是init-declarator.

  • 上述保证x = 42y = x将被单独评估.但是,正如@Praetorian在评论中正确指出的那样,脚注不是规范性的.

  • 这意味着评估的顺序没有很好地定义,并且实现者也可以以相反的顺序(即,T Dn; ...T D2; T D1;)来实现对声明的评估.

  • 有人可能会说,逗号运算符是保证从左到右的评估.但是,事实并非如此.根据K&R [K&R II,3.6 p.63],这也适用于C++:

将函数参数,声明中的变量等分开的逗号不是逗号运算符,也不保证从左到右的求值.

  • *逗号运算符*是.但这不是逗号运算符,这里只是*init-declarators的分隔符* - §8/ 1声明中出现的*init-declarator-list*是逗号分隔的声明符序列 (3认同)
  • 脚注是非规范性的.我认为脚注中的*通常*为实现提供了足够的摆动空间,以相反的顺序对它们进行评估,并且仍然符合要求. (2认同)

Sha*_*our 5

这个问题是在很早以前由comp.lang.c ++。mode主持的,主题为init-declarator-list分析顺序,结论是Yes

虽然我看到了full-expression参数,但是看不到评估参数的顺序。因此,我认为这是未指定的。

问题的相关部分是:

在此声明和定义中:

int a = 2,b = a;

是否保证b将始终初始化为2?如果是,那么我们可以说a = 2总是在b = a之前被分析(或评估吗?)。

答案的相关部分是:

是。严格说来,程序的可观察行为必须好像声明的“ a = 2”部分的所有副作用都发生在对“ b = a”部分的评估开始之前。(当然,在实践中,在这个简单的示例中,编译器可以以任意顺序或什至并行地将2分配给a和b,因为这样做会导致相同的可观察到的行为。)

再往下走:

但是,在这种特殊情况下,它会将声明符列表分隔为单独的声明符;每个声明符都包含一个完整的表达式,并且声明符按顺序求值。

更新资料

使每个init-declator成为完整表达式的原因很微妙,但据我所知,遵循的逻辑与我在初始化器中对同一变量的多次突变列出C ++ 11之前的未定义行为有关。在这种情况下,我们从第8节中定义的语法开始:

init-declarator-list:
  init-declarator
  init-declarator-list , init-declarator
init-declarator:
  declarator initializeropt
Run Code Online (Sandbox Code Playgroud)

下一个重点是初始化语法,该语法在以下部分中介绍8.5

initializer:
  brace-or-equal-initializer
  ( expression-list )
brace-or-equal-initializer:
  = initializer-clause
  braced-init-list
initializer-clause:
  assignment-expression
  braced-init-list
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,我们都有=初始化子句,这使我们进入了赋值表达式,如果我们按照第5节中的语法进行操作,则会使我们回到primary-expression,它可以为我们提供文字id-expression

因此,我们确实有用语法逗号分隔的完整表达式,因此我们具有:

int x = 42, y = x;
          ^      ^
          |      end full-expression
          end full-expression
Run Code Online (Sandbox Code Playgroud)

根据1.914段,我们看到:

在与要评估的下一个完整表达式关联的每个值计算和副作用之前,对与一个完整表达式关联的每个值计算和副作用进行排序。8。

至于评估顺序,我认为这没有指定,适用于初始化程序列表的缺陷报告430的逻辑似乎也适用于此处。在C ++ 11中,初始化器列表的语言已在部分中进行了以下补充8.5.4

在带有括号的初始列表的初始列表中,初始子句(包括由包扩展(14.5.3)导致的子句)按照它们出现的顺序进行评估。[...]

初始化器没有这样的等效项。