Win*_*one 34 c++ operator-precedence undefined-behavior initialization-order language-lawyer
考虑:
int f () {
static int i = 0;
return i++;
}
struct Test {
int a, b;
Test () : a(f()), b(f()) {}
};
Test t;
Run Code Online (Sandbox Code Playgroud)
我知道a之前b由于其声明的顺序而被初始化struct.
我也知道这两次打电话都没有f参加g(f(), f()).
所以我想知道是否保证t.a == 0和t.b == 1?
Nat*_*ica 30
所以我想知道是否保证
t.a == 0和t.b == 1?
这将始终是真实的,只要a来之前b在类声明中,并没有别的调用f()的初始化之间a和b.类成员按照在类中声明的顺序进行初始化.[class.base.init]/11:
在非委托构造函数中,初始化按以下顺序进行:[...]
- 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何).
如此以来,a来之前b那么当构造函数初始化a,它会调用f()的第一次,然后进行初始化时,它会调用它第二次b.
我们也知道成员初始化器之间有一个序列点,因为[class.base.init]/7:
[...]每个mem-initializer执行的初始化构成一个完整表达式.mem-initializer中的任何表达式都将作为执行初始化的full-expression的一部分进行计算.
告诉我们每个初始化程序都是一个完整的表达式,每个完整的表达式都是按顺序排序的:[intro.execution]/14
在与要评估的下一个全表达式相关联的每个值计算和副作用之前,对与全表达式相关联的每个值计算和副作用进行排序.
我知道a由于它们在结构中的声明顺序而在b之前初始化.
确实如此.
我对该约束的解释是,除非在a初始化之前b初始化表达式的评估完成,否则无法b初始化.
我没有在标准中看到任何关于对用于初始化非静态成员的表达式的评估进行排序的内容.但是,我在C++ 11标准(12.6.2/12)中看到以下示例:
mem-initializer的expression-list或braced-init-list中的名称在为其指定mem-initializer的构造函数的范围内进行计算.[ 例如:
Run Code Online (Sandbox Code Playgroud)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.