C++ Logo

std-proposals

Advanced search

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

From: organicoman <organicoman_at_[hidden]>
Date: Thu, 24 Feb 2022 17:22:07 +0400
From what i understand from the standardees above, is that : during the construction of an object of type T, if an exception is thrown due to an exception(i.e error) during the construction of one of its subobjects, then all the subobjects that have been constructed successfully are allowed to call their destructors to free their resources. Why? Because if the object of type T is not completely constructed then it cannot call its destructor, which in turn doesn't call its subjects destructors, which leaks resources if those subobjects are fully constructed.In your proposal, you are giving this wording a different rephrasing plus imposing an order upon the possibility of calling destructors.But remember that the compiler is free to rearrange the construction of subobjects for optimization purposes, thus by following your proposal you prevent the compiler from optimazing the order of construction. That's why the cpp standard says "potentially constructed", i.e either constructed or postponed for later construction. I hope it was clear.Nadir Sent from my Galaxy
-------- Original message --------From: Kilian Henneberger via Std-Proposals <std-proposals_at_[hidden]> Date: 2/24/22 11:08 AM (GMT+04:00) To: std-proposals_at_[hidden] Cc: Kilian Henneberger <kilis-mail_at_[hidden]> Subject: [std-proposals] Relax condition for potentially invoked destructor in constructor
    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]);
      
        
          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
        
      
    
  

Received on 2022-02-24 13:22:15