Is re-throwing an exception legal in a nested 'try'?
Asked Answered
K

2

23

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!

Kayseri answered 17/3, 2010 at 21:43 Comment(6)
I remember considering this approach to reduce code duplication arising from different try/catch blocks, but I implemented it. What makes you think it might be illegal?Pestilence
I have used this before too it is a great techniqueBreakneck
@jdv - I felt a bit uncomfortable with rethrowing from within a try block nested in a catch-clause (and even in a different stack frame). It just looked a bit too beautiful, so I wanted to be on the safe side.Kayseri
throw without arguments is deprecated in c++ 11. I used this approach in c++3 without problems however I'm getting one messy issue in g++ trying to port it (using rethrow_exception and get_exception).Lanthanum
@Lanthanum Whoah Whoah Whoah. Can you cite that source? en.cppreference.com/w/cpp/language/throw I think you maybe confusing with exception-specifications en.cppreference.com/w/cpp/language/except_spec !?Damselfish
Yup, you are right. Ty.Lanthanum
L
13

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.

Legitimacy answered 17/3, 2010 at 21:46 Comment(1)
It would be okay to use this approuch inside a method called in a constructor? (g++)Lanthanum
G
3

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.

Golf answered 17/3, 2010 at 21:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.