• Delegating constructors

    From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Tue Oct 1 10:44:15 2024
    From Newsgroup: comp.lang.c++

    I recently used C++11's delegating constructors for the first time.
    I thought that when I call a delegating constructor and I thow an
    exception from the constructor that calls the delegating constructor
    I've to call the destructor manually. But it's not like that:

    #include <iostream>

    using namespace std;

    struct S
    {
    S() { cout << "S::S()" << endl; }
    S( int ) : S() { throw invalid_argument( "sads" ); }
    ~S() { cout << "S::~S()" << endl; }
    };

    int main()
    {
    try
    {
    S s( 123 );
    }
    catch( ... )
    {
    }
    }

    Prints:

    S::S()
    S::~S()
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Tue Oct 1 13:21:08 2024
    From Newsgroup: comp.lang.c++

    On 01/10/2024 10:44, Bonita Montero wrote:
    I recently used C++11's delegating constructors for the first time.
    I thought that when I call a delegating constructor and I thow an
    exception from the constructor that calls the delegating constructor
    I've to call the destructor manually. But it's not like that:

    When you have called the delegating constructor, the object is fully constructed. The rest of the code comes after that, on the constructed
    object - so the destructor will be called as normal if there is an
    exception during the rest of the constructor.

    If you want the standard reference, it is in paragraph 4 of
    "[except.ctor]", at least in C++20 :

    """
    If the compound-statement of the function-body of a delegating
    constructor for an object exits via an exception, the object’s
    destructor is invoked. Such destruction is sequenced before entering a
    handler of the function-try-block of a delegating constructor for that
    object, if any.
    """


    #include <iostream>

    using namespace std;

    struct S
    {
        S() { cout << "S::S()" << endl; }
        S( int ) : S() { throw invalid_argument( "sads" ); }
        ~S() { cout << "S::~S()" << endl; }
    };

    int main()
    {
        try
        {
            S s( 123 );
        }
        catch( ... )
        {
        }
    }

    Prints:

    S::S()
    S::~S()

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Andrey Tarasevich@andreytarasevich@hotmail.com to comp.lang.c++ on Tue Oct 1 07:21:27 2024
    From Newsgroup: comp.lang.c++

    On 10/01/24 1:44 AM, Bonita Montero wrote:
    I recently used C++11's delegating constructors for the first time.
    I thought that when I call a delegating constructor and I thow an
    exception from the constructor that calls the delegating constructor
    I've to call the destructor manually. But it's not like that:


    Um... Why would this even be a question? Why would the idea of "calling
    the destructor manually" even enter consideration?
    --
    Best regards,
    Andrey
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Tue Oct 1 16:23:55 2024
    From Newsgroup: comp.lang.c++

    Am 01.10.2024 um 16:21 schrieb Andrey Tarasevich:

    Um... Why would this even be a question? Why would the idea of "calling
    the destructor manually" even enter consideration?

    Because I've never used delegating constructors so far and I didn't
    know where the object entered the state with complete construction.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Sam@sam@email-scan.com to comp.lang.c++ on Tue Oct 1 19:48:19 2024
    From Newsgroup: comp.lang.c++

    Bonita Montero writes:

    Am 01.10.2024 um 16:21 schrieb Andrey Tarasevich:

    Um... Why would this even be a question? Why would the idea of "calling the
    destructor manually" even enter consideration?

    Because I've never used delegating constructors so far and I didn't
    know where the object entered the state with complete construction.

    If the object already "entered the state with complete construction", then
    an explicit destructor results in UB when the destructor gets called again, for real-sies. It is fundamental to C++ that (barring immaterial
    distractions like memory leaks) C++ will invoke the destructor, guaranteed, whenever a fully-constructed object goes bye-bye.

    So, if the object was not fully constructed you will end up calling a destructor on an object that was never fully constructed. And if it was
    fully constructed, this ends up calling the destructor twice. So, either
    way, it makes no sense.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Wed Oct 2 02:36:17 2024
    From Newsgroup: comp.lang.c++

    Am 02.10.2024 um 01:48 schrieb Sam:

    If the object already "entered the state with complete construction",
    then an explicit destructor results in UB when the destructor gets
    called again, ...

    Because the constructor delegating to another constructor does also
    a part of the initialization I thought I've to call the destructor
    manually.


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Andrey Tarasevich@andreytarasevich@hotmail.com to comp.lang.c++ on Tue Oct 1 20:16:02 2024
    From Newsgroup: comp.lang.c++

    On 10/01/24 7:23 AM, Bonita Montero wrote:
    Am 01.10.2024 um 16:21 schrieb Andrey Tarasevich:

    Um... Why would this even be a question? Why would the idea of
    "calling the destructor manually" even enter consideration?

    Because I've never used delegating constructors so far and I didn't
    know where the object entered the state with complete construction.

    [except.ctor] says

    4 If the compound-statement of the function-body of a delegating constructor for an object exits via an exception, the object's
    destructor is invoked. [...]

    https://timsong-cpp.github.io/cppwp/except.ctor#4

    I.e. once the the target constructor has finished its work, the object
    is considered to be fully constructed, and it is considered to be OK to
    invoke its "full" destructor. So, if the delegating constructor body
    throws, the entire object's destructor is invoked (automatically).

    This is different from situation when regular constructor throws. In
    that case individual sub-object destructors are invoked one by one.

    But in either case, the destructor(s) is(are) invoked automatically. No
    need to do it manually.
    --
    Best regards,
    Andrey


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Wed Oct 2 05:27:36 2024
    From Newsgroup: comp.lang.c++

    Am 02.10.2024 um 05:16 schrieb Andrey Tarasevich:

    This is different from situation when regular constructor throws.
    In that case individual sub-object destructors are invoked one by one.

    Of course, but for me it wasn't obvious that the delegating constructor
    gets a completed object since I used delegation for the first time.
    --- Synchronet 3.20a-Linux NewsLink 1.114