成员初始化列表中的递增是否会生成未定义的行为?

时间:2018-01-19 12:41:34

标签: c++ language-lawyer undefined-behavior ctor-initializer

这会导致未定义的行为吗?具体来说,初始化列表中的递增以及如何评估它。

class Wrinkle {
public:
    Wrinkle(int i) : a(++i), b(++i), x(++i) {}
private:
    int a;
    int x;
    int b;
};

成员声明和初始化程序列表之间的顺序差异是有意的,因为这是一个可以准确显示差异的示例,所以请暂时忽略它。

2 个答案:

答案 0 :(得分:31)

这不会生成未定义的行为,因为:

[class.base.init]#7

  

[注意:每个mem-initializer执行的初始化构成一个完整表达式。 mem-initializer中的任何表达式都将作为执行初始化的full-expression的一部分进行计算。 ]

[intro.execution]

  

5.完整表达

     
      
  • [...]
  •   
  • init-declarator或mem-initializer,包括初始化程序的组成表达式,
  •   
     

9.每个与完整表达式相关的值计算和副作用在每个值计算和与要评估的下一个完整表达式相关的副作用之前都会被排序。

但请注意:

[class.base.init]#13

  

在非委托构造函数中,初始化按以下顺序进行:

     
      
  • [...]

  •   
  • 然后,非静态数据成员按照在类定义中声明的顺序进行初始化(再次与mem-initializers的顺序无关)。

  •   

因此,您的代码会有效地将i + 1分配给a,将i + 2分配给x,将i + 3分配给b

答案 1 :(得分:6)

C ++ 17标准包含一个示例almost exactly the same as in the question

struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
  D(int);
  B1 b;
  const int c;
};

D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
D d(10);

接下来是注释:

  

[注意:每个mem-initializer执行的初始化构成一个完整表达式(4.6)。 mem-initializer中的任何表达式都将作为执行初始化的full-expression的一部分进行计算。 - 结束说明]

点击链接后,第4.6节告诉我们其中一个definitions of "full-expression" is

  

...一个mem-initializer,包括初始化程序的组成表达式,

短语"包括初始化程序的组成表达式"强烈建议我上面的代码是合法的,因为++i的副作用将在转到下一个初始化程序之前完成。这只是我对标准的阅读,我很高兴推荐给比我更具有独立经验的人。

(还值得注意的是,成员的初始化将按照它们在类中声明的顺序发生,而不是按它们在成员初始化程序列表中出现的顺序发生。)