Should it be possible to use std::current_exception inside destructors of objects that are destroyed during stack unwinding?
Documentation on cppreference says:
If called during exception handling (typically, in a catch clause), captures the current exception object (...)
But it's not clear for me whether stack unwinding is a part of exception handling.
In some highest-ranked answer on stackoverflow author assumes that it's possible.
I did some test on my compiler (g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2) and it seems, that std::current_exception returns empty pointer in this case.
#include <exception> #include <stdexcept> #include <iostream> struct A { ~A() { std::clog << "in destructor"<<std::endl; std::clog << "uncaught_exception: " << std::uncaught_exception() << std::endl; std::clog << "current_exception: " << (bool)std::current_exception() << std::endl; } }; int main(int argc, char **) { try { A aa; std::clog << "before throw"<<std::endl; if(argc>1) throw std::runtime_error("oh no"); } catch(...) { std::clog << "in catch block"<<std::endl; std::clog << "uncaught_exception: " << std::uncaught_exception() << std::endl; std::clog << "current_exception: " << (bool)std::current_exception() << std::endl; } return 0; }
The output is:
before throw in destructor uncaught_exception: 1 current_exception: 0 in catch block uncaught_exception: 0 current_exception: 1
Does anybody know what the standard says?
When an exception is thrown and control passes from a try block to a handler, the C++ run time calls destructors for all automatic objects constructed since the beginning of the try block. This process is called stack unwinding. The automatic objects are destroyed in reverse order of their construction.
If an exception is not caught, it is intercepted by a function called the uncaught exception handler. The uncaught exception handler always causes the program to exit but may perform some task before this happens.
C++ Standard defines current_exception()
in section § 18.8.5 [propagation] :
(emphasis mine)
exception_ptr current_exception() noexcept;
Returns: An exception_ptr object that refers to the currently handled exception (15.3) or a copy of the currently handled exception, or a null exception_ptr object if no exception is being handled. The referenced object shall remain valid at least as long as there is an exception_ptr object that refers to it.
And § 15.3 [except.handle], notes 7 and 8 :
A handler is considered active when initialization is complete for the parameter (if any) of the catch clause. [ Note: The stack will have been unwound at that point. — end note ]
The exception with the most recently activated handler that is still active is called the currently handled exception.
The exception returned by current_exception()
is defined as the "currently handled exception", which is the exception of the most recent active handler, and a handler is active only when stack unwinding completed.
As your tests have shown, there is no "active handler" during stack unwinding, so there is no "currently handled exception" either : in that case, current_exception()
will return a null exception_ptr
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With