Search code examples
c++exceptionraii

C++ using RAII with destructor that throws


Let say I have RAII class:

class Raii {
    Raii() {};
    ~Raii() { 
        if (<something>) throw std::exception();
    }
};

And if I have the function:

void foo() {
    Raii raii;    

    if (something) {
       throw std::exception();
    }
} 

This is bad because while cleaning for the first exception we can throw again and this will terminate the process.

My question is - What is a good pattern to use raii for code that the cleanup might throw?

For example is this good or bad - why?

class Raii {
    Raii() {};
    ~Raii() {
        try {
           if (<something>) throw std::exception();
        }
        catch (...) {
           if (!std::uncaught_exception())
               throw;
        }
    }
};

Note that Raii object is always stack-allocated object - and this is not the general throw from destructor problem.


Solution

  • C++ will almost certainly have a function to obtain the current exception count as of C++1z (aka C++17 if they publish it on time!): std::uncaught_exceptions (note the plural "s"). Also, destructors are declared as noexcept by default (meaning that if you attempt to exit a destructor via an exception, std::terminate is called).

    So, first, mark your destructor as throwing (noexcept(false)). Next, track the number of active exceptions in ctor, compare it to the value in dtor: if there are more uncaught exceptions in the dtor, you know that you are currently in the process of stack unwinding, and throwing again will result in a call to std::terminate.

    Now you decide exactly how exceptional you really are and how you wish to handle the situation: terminate the program, or just swallow the inner exception?

    A poor imitation is to not throw if uncaught_exception (singular) returns true, but that makes the exceptions not work when called from a different dtor's triggered by unrolling that is trying to catch and process your exception. This option is available in current C++ standards.