33

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?

Community
  • 1
  • 1
peper0
  • 3,111
  • 23
  • 35

1 Answers1

25

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 :

  1. 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 ]

  2. 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.

quantdev
  • 23,517
  • 5
  • 55
  • 88
  • " there is no "active exception" during stack unwinding" unless an exception is being handled by a catch in or invoked from a destructor. – Cheers and hth. - Alf Feb 02 '15 at 04:11
  • @Cheersandhth.-Alf True, I corrected the wording, please read no "active handler" (wording of the standard) – quantdev Feb 02 '15 at 04:15
  • Well, it's so difficult to get right that Some™ suspect that might be the reason for `std::uncaught_exception` being unusable for any purpose. ;-) – Cheers and hth. - Alf Feb 02 '15 at 04:20
  • That appears to be correct. I was surprised as well; I can see good uses for peaking at exceptions in d'tors; particularly RAII-based logging. – Ben May 25 '20 at 13:43