C++ Logo

std-proposals

Advanced search

[std-proposals] Relax condition for potentially invoked destructor in constructor

From: Kilian Henneberger <kilis-mail_at_[hidden]>
Date: Thu, 24 Feb 2022 08:08:49 +0100
Hello,

https://eel.is/c++draft/class.base.init#12 says:
/In a non-delegating constructor, the destructor for each potentially
constructed subobject of class type is potentially invoked
(//[class.dtor] <https://eel.is/c++draft/class.dtor>//);/

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] <https://eel.is/c++draft/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

Received on 2022-02-24 07:08:50