Search code examples
c++exceptiongccterminate

Throwing during unwinding -- why does this example work?


Consider this:

void thrower () {
    throw "123";
}

struct Catcher {
    ~ Catcher () {
        try {thrower ();}
        catch (...) {}
    }
};

int main () {
    try {
       Catcher c;
       throw 1.23;
    }
    catch (...) {}
}

This compiles and runs without calling terminate on gcc 4.3, but according to the standard (15.5.1)

...when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (15.1), calls a user function that exits via an uncaught exception... terminate shall be called.

When ~Catcher is called after the double has been thrown, this is "after completing evaluation...before the exception is caught" and thrower is "a user function that exits via an uncaught exception", this satisfies the above condition. Yes, the char* is caught but only after the user function exits.

Shouldn't terminate have been called?

To emphasise this:

void do_throw () {
    throw "123";
}

void thrower () {
    do_throw ();
    // Uncaught exception here (A)
}

struct Catcher {
    ~ Catcher () {
        try {thrower (); /* (B) */}
        catch (...) {}
    }
};

int main () {
    try {
       Catcher c;
       throw 1.23;
    }
    catch (...) {}
}

(A) happens in the context of (B), which already has an exception in progress.

So, shouldn't terminate have been called? If not, and this is a legal situation in which we can have two simultaneous exceptions, where do we draw the line?


Solution

  • Different emphasis:

    when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (15.1), calls a user function that exits via an uncaught exception... terminate shall be called

    thrower() is a user function that exits via an exception but it is not called by the exception handling mechanism; it is called by another user function (Catcher's destructor) which itself is called by the exception handling mechanism and this function doesn't exit via an exception.