2

The idea is "try you(), if it fails try _do(), if it fails report the exception from the first try, i.e., you()".

void that_thing() {
    try {
        you();
    } catch( ... ) {
        bool error=false;
        try {
            _do();
        } catch( ... ) {
            error = true;
        }
        if( error ) throw;
    }
}

Testing with Gcc it worked fine, I was wondering if it will work with any compiler. Just to be clearer, the weird behavior I was expecting was that the throw; would rethrow the inner exception.

Edit: This question is NOT about the inner most catch, it is about rethrowing the outer exception after catching the inner most. The question is if this kind of rethrowing is legally definitely was not approached on the question that are being pointed as similar.

André Puel
  • 8,741
  • 9
  • 52
  • 83
  • . I'd say "of course it wouldn't re-throw the inner exception". Consider a simple `try { foo(); } catch(...) { bar(); throw; }`. I've never seen anyone worry about what this does when `bar` internally throws and catches an exception. Could you expand a bit on why you think the inner exception might be re-thrown? A more specific question can get a better answer. –  Sep 03 '14 at 08:40
  • Without consulting the standard or having any special knowledge about this issue I would hazard a guess that it's just fine and the compiler *must* track the outermost exception. Otherwise if `_do()` used `try/catch` itself behind the scenes and an it just swallowed the exception *and it got inlined* (or even not inlined?), bad things would happen to your code. – ta.speot.is Sep 03 '14 at 08:43
  • @hvd I was thinking if you have a naive exception mechanism which uses a global pointer to the "current exception", this current exception would be replace upon the second catch, thus giving the undesired behavior on the rethrow directive. – André Puel Sep 03 '14 at 08:43
  • @AndréPuel Ah, okay. Yes, it doesn't work like that. I'll check to see if I can find a good reference for an answer. –  Sep 03 '14 at 08:46

1 Answers1

6

The standard requires implementations to properly nest exceptions. To quote from the standard:

15.1 Throwing an exception [except.throw]

...

8 A throw-expression with no operand rethrows the currently handled exception (15.3).

15.3 Handling an exception [except.handle]

...

7 A handler is considered active when initialization is complete for the formal parameter (if any) of the catch clause. ... A handler is no longer considered active when the catch clause exits or when std::unexpected() exits after being entered due to a throw.

8 The exception with the most recently activated handler that is still active is called the currently handled exception.

When your code reaches the throw;, the inner exception handler is no longer active: the catch clause has exited. The outer exception handler is still active: it has not yet exited, and std::unexpected() has not been called. Therefore, implementations must support this usage, and re-throw the outer exception. A global "current exception" pointer that gets cleared after the inner handler exits would not match the requirements of the C++ standard.

Community
  • 1
  • 1