Below there is also a motivating note
https://eel.is/c++draft/class.base.init#note-5:
This provision ensures that destructors can be called for
fully-constructed subobjects in case an exception is thrown
([except.ctor]).
The note makes sense. But I think the paragraph #12 is too
restrict. See following example:
---
class PublicInterface {
std::unique_ptr<class Impl> pimpl_;
};
---
For the (compiler generated) default constructor of
PublicInterface, class.base.init#12
requires that the destructor of
pimpl_
is potentially invoked,
even if there is no possible code path in the (compiler
generated) default constructor of
PublicInterface
which actually might invoke it.
I would like to propose to relax paragraph #12. I am not a
wording-expert, but in my own words I would change it to
something like:
"In a non-delegating constructor of type T, the destructor for
each potentially constructed subobject S of class type is
potentially invoked,
if there is any potentially throwing code after the
construction of S and before the end of the constructor of T."
Here are a few examples for what I am aiming at:
---
class FirstExample {
std::string a_; //destructor is
potentially invoked, because the constructor of
b_ (taking a
const
char*) isn't noexcept.
std::string b_ = "Hello"; //destructor is not potentially
invoked, because the constructor of
c_
(default constructor) is noexcept.
std::string c_; //destructor is not
potentially invoked, because there are no further member.
};
class SecondExample {
std::string d_; //destructor is potentially
invoked, because the initializer of
e_
(
new int) can throw.
int* e_ = new int;
};
void ThisCanThrow();
class ThirdExample {
std::string f_;
ThirdExample() { ThisCanThrow(); } //destructor of
f_ is potentially invoked, because
the body of the constructor of
ThirdExample
calls a potentially throwing function.
};
---
I would very much welcome your feedback.
Best Regards
Kilian