views:

176

answers:

2

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!

+8  A: 

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.

GMan
+2  A: 

Since dispatcher called in the catch block throw will rethrow exception. If you will call dispatcher outside catch block then terminate() will be called (according to 15.1/8). There is no undefined behavior in any case.

Kirill V. Lyadvinsky