This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115c. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-09-25


104. Destroying the exception temp when no handler is found

Section: 14.2  [except.throw]     Status: NAD     Submitter: Jonathan Schilling     Date: 21 Mar 1999

Questions regarding when a throw-expression temporary object is destroyed.

Section 14.2 [except.throw] paragraph 4 describes when the temporary is destroyed when a handler is found. But what if no handler is found:

    struct A {
        A() { printf ("A() \n"); }
        A(const A&) { printf ("A(const A&)\n"); }
        ~A() { printf ("~A() \n"); }
    };

    void t() { exit(0); }

    int main() {
        std::set_terminate(t);
        throw A();
    }
Does A::~A() ever execute here? (Or, in case two constructions are done, are there two destructions done?) Is it implementation-defined, analogously to whether the stack is unwound before terminate() is called (14.4 [except.handle] paragraph 9) ?

Or what if an exception specification is violated? There are several different scenarios here:

    int glob = 0; // or 1 or 2 or 3

    struct A {
        A() { printf ("A() \n"); }
        A(const A&) { printf ("A(const A&)\n"); }
        ~A() { printf ("~A() \n"); }
    };

    void u() {
        switch (glob) {
        case 0:  exit(0);
        case 1:  throw "ok";
        case 2:  throw 17;
        default: throw;
        }
    }

    void foo() throw(const char*, std::bad_exception) {
        throw A();
    }

    int main() {
        std::set_unexpected(u);
        try {
            foo();
        }
        catch (const char*) { printf("in handler 1\n"); }
        catch (std::bad_exception) { printf("in handler 2\n"); }
    }
The case where u() exits is presumably similar to the terminate() case. But in the cases where the program goes on, A::~A() should be called for the thrown object at some point. But where does this happen? The standard doesn't really say. Since an exception is defined to be "finished" when the unexpected() function exits, it seems to me that is where A::~A() should be called — in this case, as the throws of new (or what will become new) exceptions are made out of u(). Does this make sense?

Rationale (10/99): Neither std::exit(int) nor std::abort() destroys temporary objects, so the exception temporary is not destroyed when no handler is found. The original exception object is destroyed when it is replaced by an unexpected() handler. The Standard is sufficiently clear on these points.