Please help me with this program:
struct U {
U(int *) noexcept;
private:
~U() noexcept;
};
struct B {
B();
~B();
U v; //ok
U w{nullptr}; //ok
U u = nullptr; //error
};
Here struct U
has a private destructor only for demonstration that the destructor is not really invoked by the compiler and to simplify the length of the code.
And struct B
has only declared a default constructor and destructor, so the compiler will not generate them in this translation unit.
Also struct B
has 3 fields: v
, w
and u
. There is no problem with the v
and w
fields, but for field u
the compiler issues an error about an inaccessible destructor for U
:
error: 'U::~U()' is private within this context
13 | U u = nullptr; //error
Demo: https://gcc.godbolt.org/z/YooGe9xq6
The questions are:
B::B()
is not compiled in this translation unit, why is field default initialization considered at all?u
field? (No mandatory copy elision?)u
and w
cases then?If B::B() is not compiled in this translation unit, why field default initialization is considered at all?
Because member initialization is part of the class' definition. So it's the class definition itself that's invalid, without having to involve the definition of its constructor(s). In the standard, you can start from [class.mem.general] and follow through brace-or-equal-initializer
, which eventually requires a valid "bog-standard" assignment-expression.
Is the error because of a temporary object created for the initialization of u field? (No mandatory copy elision?)
Yes, the compiler error in your godbolt link is clear about that:
<source>:13:11: error: temporary of type 'U' has private destructor
U u = nullptr; //error
see Why is public destructor necessary for mandatory RVO in C++? for an explanation on why mandatory copy-elision doesn't apply (Thanks @NathanPierson!)
What is the difference between u and w cases then?
w
is initialized directly without creating a temporary beforehand so creating it works fine because nothing in the expression ever tries to invoke the destructor of U
. Obviously any definition of B::~B()
would still fail on w
, but that's beyond the point.