函数调用是否在构造函数的初始化列表中排序?

时间:2017-04-18 18:39:45

标签: c++ language-lawyer undefined-behavior operator-precedence initialization-order

考虑:

int f () {
    static int i = 0;
    return i++;
}

struct Test {
    int a, b;
    Test () : a(f()), b(f()) {}
};

Test t;

我知道由于a中的声明顺序,b已在struct之前初始化。

我也知道f中对g(f(), f())的两次调用都没有排序。

所以我想知道是否保证t.a == 0t.b == 1

2 个答案:

答案 0 :(得分:30)

  

所以我想知道是否保证t.a == 0t.b == 1

只要a出现在类声明中的b之前,并且在f()和{{1}的初始化之间没有其他任何内容调用a,这将始终为真。 }。类成员按照在类中声明的顺序进行初始化。 [class.base.init] / 11:

  

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

     
      
  • 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何)。
  •   

因为ba之前出现,所以当构造函数初始化b时,它将第一次调用a,然后在初始化时第二次调用f() b

我们也知道成员初始化程序之间存在一个序列点,因为[class.base.init] / 7:

  

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

告诉我们每个初始化程序都是一个完整的表达式,并且每个完整的表达式都是有序的:[intro.execution] / 14

  

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

答案 1 :(得分:6)

  

我知道a在b之前被初始化,因为它们在结构中的声明顺序。

这是真的。

我对该约束的解释是a无法在b之前初始化,除非在b初始化之前初始化表达式的评估已完成。

我没有在标准中看到任何关于对用于初始化非静态成员的表达式的评估进行排序的内容。但是,我在C ++ 11标准(12.6.2 / 12)中看到以下示例:

  

mem-initializer的expression-list或braced-init-list中的名称在为其指定mem-initializer的构造函数的范围内计算。 [示例:

class X {
  int a;
  int b;
  int i;
  int j;
  public:
  const int& r;
  X(int i): r(a), b(i), i(i), j(this->i) { }
};

除非在this->i初始化后对i的评估进行排序,否则无效。