Is the following well-defined in C++, or not? I am forced to 'convert' exceptions to return codes (the API in question is used by many C users, so I need to make sure all C++ exceptions are caught & handled before control is returned to the caller).
enum ErrorCode {…}; ErrorCode dispatcher() { try { throw; } catch (std::bad_alloc&) { return ErrorCode_OutOfMemory; } catch (std::logic_error&) { return ErrorCode_LogicError; } catch (myownstdexcderivedclass&) { return ErrorCode_42; } catch(...) { return ErrorCode_UnknownWeWillAllDie; } } ErrorCode apifunc() { try { // foo() might throw anything foo(); } catch(...) { // dispatcher rethrows the exception and does fine-grained handling return dispatcher(); } return ErrorCode_Fine; } ErrorCode apifunc2() { try { // bar() might throw anything bar(); } catch(...) { return dispatcher(); } return ErrorCode_Fine; }
I hope the sample shows my intention. My guess is that this is undefined behaviour, but I'm not sure. Please provide quotes from the standard, if applicable. Alternative approaches are appreciated as well.
Thanks!
Nesting try-catch blocks severely impacts the readability of source code because it makes it to difficult to understand which block will catch which exception.
A nested exception is an exception that occurs while another exception is being handled. When this happens, the processing of the first exception is temporarily suspended. Exception handling begins again with the most recently generated exception.
After throwing an exception, you do not need to return because throw returns for you. Throwing will bubble up the call stack to the next exception handler so returning is not required.
If a function throws an exception and that exception isn't caught in main program will crash badly.
That's fine. The exception is active until it's caught, where it becomes inactive. But it lives until the scope of the handler ends. From the standard, emphasis mine:
§15.1/4: The memory for the temporary copy of the exception being thrown is allocated in an unspecified way, except as noted in 3.7.4.1. The temporary persists as long as there is a handler being executed for that exception.
That is:
catch(...) { // <-- /* ... */ } // <--
Between those arrows, you can re-throw the exception. Only when the handlers scope ends does the exception cease to exist.
Keep in mind if you call dispatch
without an active exception, terminate
will be called. If dispatch
throws an exception in one if it's handlers, that exception will begin to propagate. More information in a related question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With