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

生来就可爱ヽ(ⅴ<●) 提交于 2020-02-02 11:27:12

问题


Consider this 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. Is it allowed by the standard to call a member function in a default member initializer?

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.


回答1:


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. So, if we look at when we can call a member function we find [class.cdtor]/1 and [class.cdtor]/4 which states:

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]).[...]

emphasis mine

Since the constructor has begun executing, and we are allowed to call member functions, we are not in UB land.

The next thing we have to consider is construction order, since the members depend on that. That information is in [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).

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.

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.




回答2:


The standard says 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.

Since you have no base classes, the member functions can be called for broken even if it is under construction. Your a will be initialized with indeterminate value.

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. So not the call of this function in itself, but rather what it does is UB.



来源:https://stackoverflow.com/questions/58958637/is-it-allowed-to-call-a-non-static-member-function-in-a-default-member-initializ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!