In the following code, compiled with Clang 8.0.0+ and -std=c++17, creating a derived class instance using B{} gives an error error: temporary of type 'A' has protected destructor. Why is A appearing in this message when the temporary has type B (and thus should have a public destructor)?
class A {
protected:
A() = default;
~A() = default;
};
class B : public A {
// can also omit these 3 lines with the same result
public:
B() = default;
~B() = default;
};
void foo(const B&) {}
int main() {
// error: temporary of type 'A' has protected destructor
foo(B{});
// ^
return 0;
}
This is a subtle issue of aggregate initialization before C++20.
Before C++20,
B(andA) are aggregate types:(emphasis mine)
Then
So
B{}constructs a temporary object via aggregate initialization, which will initialize the base subobject directly with empty list, i.e. perform aggregate initialization to construct theAbase subobject. Note that the constructor ofBis bypassed. The problem is that in such context, theprotecteddesctructor can't be called to destroy the directly constructed base subobject of typeA. (It doesn't complain about theprotectedconstructor because it's bypassed by the aggregate initialization ofAtoo.)You can change it to
foo(B());to avoid aggregate initialization;B()performs value-initialization, the temporary object will be initialized byB's constructor, then anything is fine.BTW since C++20 you code will work fine.
B(andA) are not aggregate types again.B{}performes list initialization, and then the temporary object is initialized byB's constructor; the effect is just same asB().