23

The code I want to execute in my exception handler may itself throw an exception.

Is the follow structure legal C++? If yes, are there any downsides?

try
{
    // ...
}
catch (const E&)
{
    try
    {
        // ...
    }
    catch (const F&)
    {

    }
}
paperjam
  • 8,321
  • 12
  • 53
  • 79

2 Answers2

29

Actually, there is even an interesting technique for using nested try/catch-blocks: assume you have multiple functions which need effectively the same exception handling. Especially when wrapping another interface this is common scenario. In this case it is possible to catch all exceptions, call a function from the exception handler, and in this function rethrow the exception to implement the actual exception handling:

void fancy_handler() {
    try {
        throw; // assumes that fancy_handler() is called from catch-clause
    } catch (std::runtime_error const& rt) {
        std::cout << "runtime-error: " << ex.what() << "\n";
    } catch (std::exception const& ex) {
        std::cout << "excption: " << ex.what() << "\n";
    } catch (...) {
        std::cout << "unknown exception\n";
    }
}

void foo() { try { do_foo(); } catch (...) { fancy_handler(); } }
void bar() { try { do_bar(); } catch (...) { fancy_handler(); } }

I just love avoiding duplicate [non-trivial] code!

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    wait, can you really `throw` from a nested function? I've never seen such a thing! – Mooing Duck Jan 03 '12 at 20:52
  • 2
    @MooingDuck: as long as you called the function from a catch-block, you can rethrow the exception. What is even more interesting is that this also works in Java and C# (I used this technique originally in Java to deal with a huge number of different database exceptions; I was the C++ expert not the Java expert, though ;) – Dietmar Kühl Jan 03 '12 at 20:56
  • I'll have to look in the standard and learn the details, and corners. – Mooing Duck Jan 03 '12 at 21:22
  • 1
    @MooingDuck: I can only tell you for C++: except.handle paragraph 7: "A handler is considered active when initialization is complete for the formal parameter (if any) of the catch clause." and except.throw pragraph 8: "A throw-expression with no operand rethrows the currently handled exception [...]". – Dietmar Kühl Jan 03 '12 at 21:38
  • The bit I was looking up specificically was `int main() {fancy_handler();}` – Mooing Duck Jan 03 '12 at 21:43
  • @MooingDuck: well, as this is a rethrow without active exception, this calls std::terminate() (see except.throw paragraph 9: "If no exception is presently being handled, executing a throw-expression with no operand calls std:: terminate()."). ... or, put differently, fancy_handler() has a precondition, although an odd one: it can only be called from within a catch block. – Dietmar Kühl Jan 03 '12 at 21:46
25

No, there are no downsides. That's the way you should do it.

ronag
  • 49,529
  • 25
  • 126
  • 221