是否允许在默认成员初始值设定项中调用非静态成员函数?
Is it allowed to call a non-static member function in a default member initializer?
考虑这个 class:
#include <iostream>
struct foo {
int a = 42;
int b = bar();
int bar() { return a; }
};
int main(){
foo f;
std::cout << f.a << " " << f.b;
}
它打印出预期的 42 42
。标准是否允许在默认成员初始值设定项中调用成员函数?
以下我认为是未定义的:
struct broken {
int a = bar();
int b = 42;
int bar() { return b; }
};
不幸的是 compile without warnings。
标准说here:
Member functions (including virtual member functions, [class.virtual]) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator ([expr.typeid]) or of a dynamic_cast ([expr.dynamic.cast]). However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the program has undefined behavior.
因为你没有基类,所以broken
即使在构造中也可以调用成员函数。 您的 a
将被初始化为不确定的值。
我有点早熟。正如在另一个答案中看到的那样,存在一个问题,即函数从未定义行为的未初始化值中读取。所以不是这个函数本身的调用,而是它所做的是 UB。
如您所见,这是合法的,但很脆弱,不推荐使用。当您为 class 成员指定默认初始化程序时,这些只是在 class 成员初始化程序列表中使用此值的语法糖。所以,如果我们看看什么时候可以调用成员函数,我们会发现 [class.cdtor]/1 and [class.cdtor]/4 表示:
1) For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.
4) Member functions, including virtual functions ([class.virtual]), can be called during construction or destruction ([class.base.init]).[...]
强调我的
既然构造函数已经开始执行,并且允许我们调用成员函数,我们就不在UB领域了。
接下来我们要考虑的是构造顺序,因为成员依赖于它。该信息在 [class.base.init]/13
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
因此,成员是按照它们在 class 中声明的顺序构造的,这意味着在您的第一个示例中,您在 a
初始化后引用它,因此您不在 UB 土地中.
在您的第二个示例中,您指的是一个尚未初始化的对象,读取未初始化对象的值是未定义的行为。
考虑这个 class:
#include <iostream>
struct foo {
int a = 42;
int b = bar();
int bar() { return a; }
};
int main(){
foo f;
std::cout << f.a << " " << f.b;
}
它打印出预期的 42 42
。标准是否允许在默认成员初始值设定项中调用成员函数?
以下我认为是未定义的:
struct broken {
int a = bar();
int b = 42;
int bar() { return b; }
};
不幸的是 compile without warnings。
标准说here:
Member functions (including virtual member functions, [class.virtual]) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator ([expr.typeid]) or of a dynamic_cast ([expr.dynamic.cast]). However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the program has undefined behavior.
因为你没有基类,所以broken
即使在构造中也可以调用成员函数。 您的 a
将被初始化为不确定的值。
我有点早熟。正如在另一个答案中看到的那样,存在一个问题,即函数从未定义行为的未初始化值中读取。所以不是这个函数本身的调用,而是它所做的是 UB。
如您所见,这是合法的,但很脆弱,不推荐使用。当您为 class 成员指定默认初始化程序时,这些只是在 class 成员初始化程序列表中使用此值的语法糖。所以,如果我们看看什么时候可以调用成员函数,我们会发现 [class.cdtor]/1 and [class.cdtor]/4 表示:
1) For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.
4) Member functions, including virtual functions ([class.virtual]), can be called during construction or destruction ([class.base.init]).[...]
强调我的
既然构造函数已经开始执行,并且允许我们调用成员函数,我们就不在UB领域了。
接下来我们要考虑的是构造顺序,因为成员依赖于它。该信息在 [class.base.init]/13
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
因此,成员是按照它们在 class 中声明的顺序构造的,这意味着在您的第一个示例中,您在 a
初始化后引用它,因此您不在 UB 土地中.
在您的第二个示例中,您指的是一个尚未初始化的对象,读取未初始化对象的值是未定义的行为。