C++ 是否允许在默认成员初始值设定项中调用非静态成员函数?

C++ 是否允许在默认成员初始值设定项中调用非静态成员函数?,c++,constructor,initialization,language-lawyer,member-initialization,C++,Constructor,Initialization,Language Lawyer,Member Initialization,以这一类为例: #include <iostream> struct foo { int a = 42; int b = bar(); int bar() { return a; } }; int main(){ foo f; std::cout << f.a << " " << f.b; } 不幸的是,它确实如此。标准上说: 可以为正在构造的对象调用成员函数(包括虚拟成员函数[class.virtua

以这一类为例:

#include <iostream>

struct foo {
    int a = 42;
    int b = bar();
    int bar() { return a; }
};

int main(){
    foo f;
    std::cout << f.a << " " << f.b;
}
不幸的是,它确实如此。

标准上说:

可以为正在构造的对象调用成员函数(包括虚拟成员函数[class.virtual])。类似地,正在构造的对象可以是typeid运算符([expr.typeid])或动态转换([expr.dynamic.cast])的操作数。但是,如果这些操作在基类的所有mem初始值设定项完成之前在ctor初始值设定项(或直接或间接从ctor初始值设定项调用的函数)中执行,则程序具有未定义的行为

由于您没有基类,因此即使成员函数正在构造中,也可以为其调用
breaked
。您的
a
将使用不确定值初始化


我有点早熟。正如在另一个答案中所看到的,有一个问题,函数从一个未定义行为的单位化值读取。因此,不是调用这个函数本身,而是它所做的是UB。

正如您所发现的,这是合法的,但很脆弱,不推荐使用。当您为类成员指定默认初始值设定项时,这些只是在类成员初始值设定项列表中使用此值的语法糖。因此,如果我们看看何时可以调用成员函数,我们会发现哪些状态:

1) 对于具有非平凡构造函数的对象,在构造函数开始执行之前引用对象的任何非静态成员或基类会导致未定义的行为。对于具有非平凡析构函数的对象,在析构函数完成执行后引用该对象的任何非静态成员或基类会导致未定义的行为

4) 成员函数,包括虚拟函数([class.virtual]),可以在构造或销毁([class.base.init])期间调用。[…]

重点矿山

由于构造函数已经开始执行,并且允许我们调用成员函数,所以我们不在UB区域

下面我们要考虑的是构造顺序,因为成员依赖于此。这一信息是公开的

然后,按照类定义中声明的顺序初始化非静态数据成员(同样,与mem初始值设定项的顺序无关)

因此,成员是按照它们在类中声明的顺序构造的,这意味着在您的第一个示例中,您在初始化后引用了
a
,因此您不在UB-land中


在第二个示例中,您引用的是尚未初始化的对象,读取未初始化对象的值是未定义的行为。

如果这些操作是在ctor初始值设定项中执行的(或在直接或间接从ctor初始值设定项调用的函数中执行的),则可能遗漏了“但是”在基类的所有mem初始值设定项完成之前,程序具有未定义的行为。“。最好在答案中包含文本我可以将文本复制到答案中,但这对您的示例没有影响,因为它没有基类。或者我在读这篇文章的时候错过了什么?哦,对不起,我错过了基本类的东西。然而,答案应该是自我控制的,不会造成伤害。谢谢你的提示,我对这整件事还是有点陌生^^
struct broken {
    int a = bar();
    int b = 42;       
    int bar() { return b; }
};