简体   繁体   English

是否允许在默认成员初始化程序中调用非静态成员 function?

[英]Is it allowed to call a non-static member function in a default member initializer?

Consider this class:考虑这个 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;
}

It prints the expected 42 42 .它打印预期的42 42 Is it allowed by the standard to call a member function in a default member initializer?标准是否允许在默认成员初始化程序中调用成员 function?

The following I would expect to be undefined:以下我希望是未定义的:

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

Unfortunately it does compile without warnings .不幸的是,它编译时没有警告

As you found, this is legal, but brittle and not recommended.如您所见,这是合法的,但很脆弱,不推荐。 When you specify default initializers for class members those are just syntactic sugar for use this value in the class member initializer list.当您为 class 成员指定默认初始化程序时,这些只是在 class 成员初始化程序列表中使用此值的语法糖。 So, if we look at when we can call a member function we find [class.cdtor]/1 and [class.cdtor]/4 which states:因此,如果我们查看何时可以调用成员 function,我们会发现[class.cdtor]/1[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 . 1) 对于具有非平凡构造函数的 object ,在构造函数开始执行之前引用 object 的任何非静态成员或基 class 会导致未定义的行为 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.对于具有非平凡析构函数的 object,在析构函数完成执行后引用 object 的任何非静态成员或基 class 会导致未定义的行为。

4) Member functions, including virtual functions ([class.virtual]), can be called during construction or destruction ([class.base.init]).[...] 4)成员函数,包括虚函数([class.virtual]),可以在构造或销毁([class.base.init])期间调用。[...]

emphasis mine强调我的

Since the constructor has begun executing, and we are allowed to call member functions, we are not in UB land.由于构造函数已经开始执行,并且我们被允许调用成员函数,我们不在 UB 领域。

The next thing we have to consider is construction order, since the members depend on that.接下来我们要考虑的是构造顺序,因为成员依赖于它。 That information is in [class.base.init]/13该信息在[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 定义中声明的顺序进行初始化(同样不管 mem 初始化程序的顺序)。

So, the members are constructed in the order they are declared in the class which means in your first example you refer to a after it has been initialized so you are not in UB land.因此,成员是按照它们在 class 中声明的顺序构建的,这意味着在您的第一个示例中,您在初始化之后引用a ,因此您不在 UB 土地中。

In your second example you are referring to an object that has not yet been initialized and reading an uninitialized object's value is undefined behavior.在您的第二个示例中,您指的是尚未初始化的 object 并且读取未初始化对象的值是未定义的行为。

The standard says here :标准在这里说:

Member functions (including virtual member functions, [class.virtual]) can be called for an object under construction.可以为正在构建的 object 调用成员函数(包括虚拟成员函数,[class.virtual])。 Similarly, an object under construction can be the operand of the typeid operator ([expr.typeid]) or of a dynamic_cast ([expr.dynamic.cast]).类似地,正在构建的 object 可以是 typeid 运算符 ([expr.typeid]) 或 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.但是,如果这些操作在基类的所有 mem-initializer 完成之前在 ctor-initializer(或直接或间接从 ctor-initializer 调用的 function 中)中执行,则程序具有未定义的行为。

Since you have no base classes, the member functions can be called for broken even if it is under construction.由于您没有基类,因此即使正在构建成员函数也可以调用broken Your a will be initialized with indeterminate value.a将被初始化为不确定的值。

I was a bit premature.我有点为时过早。 As seen in the other answer, there is the problem, that the function reads from an unitialized value which is undefined behavior.如在另一个答案中所见,存在问题,function 从未定义行为的未初始化值读取。 So not the call of this function in itself, but rather what it does is UB.所以不是这个 function 本身的调用,而是它所做的是 UB。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM