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:
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