Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ISO c++ 15.3.10 : Why is this undefined behaviour?

From the related c++ standard section :

Referring to any non-static member or base class of an object in the handler for a function-try-block of a constructor or destructor for that object results in undefined behavior.

eg.

T::~T() 
{
      try {
        this->nonstatic_member; // iff I read the quote correctly
      } catch( ... ) {
      }
}

So why is this undefined behaviour ?

like image 589
Nikos Athanasiou Avatar asked Dec 04 '22 06:12

Nikos Athanasiou


1 Answers

I think the reason why accessing non-static data members in a function-try-block of a destructor is that [except.ctor]/2 and [except.handle]/11 guarantee that all subobjects have already been destroyed when entering the catch-clause of said try-block:

github draft from 2014-07-23, [except.ctor]/2

An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor has completed execution and the destructor has not yet begin execution.

[except.handle]/11

[...] The base classes and non-variant members of an object shall be destroyed before entering the handler of a function-try-block of a destructor for that object.

Therefore, whether we throw the exception in the dtor of the class itself, or in the dtor of a subobject: all subobjects will be destroyed.


Example 1:

#include <iostream>

struct loud
{
    ~loud() { std::cout << "~loud()\n"; }
};

struct T
{
    loud l;
    
    ~T() noexcept(false)
    try
    {
        std::cout << "throwing an int\n";
        throw 42;
    }catch(int)
    {
        std::cout << "caught an int\n";
        throw;
    }
};

int main()
{
    try
    {
        T t;
    }catch(...)
    {
        std::cout << "caught an exception in main\n";
    }
}

Output:

throwing an int
~loud()
caught an int
caught an exception in main

Live example


Example 2:

#include <iostream>

struct loud
{
    loud() { std::cout << "loud()\n"; }
    ~loud() { std::cout << "~loud()\n"; }
};

struct A
{
    A() { std::cout << "A()\n"; }
    ~A() noexcept(false) { std::cout << "~A()\n"; throw 42; }
};

struct T
{
    loud l;
    A a;
    
    ~T() noexcept(false)
    try
    {
    }catch(int)
    {
        std::cout << "caught an int\n";
        throw;
    }
};

int main()
{
    try
    {
        T t;
    }catch(...)
    {
        std::cout << "caught an exception in main\n";
    }
}

Output:

loud()
A()
~A()
~loud()
caught an int
caught an exception in main

Live example

like image 196
dyp Avatar answered Dec 27 '22 21:12

dyp