5

If I have a code like the following:

try {
  doSomething();
} catch (...) {
  noteError();
}

void noteError() {
  try {
    throw;
  } catch (std::exception &err) {
    std::cerr << "Note known error here: " << err.what();
  } catch (...) {
    std::cerr << "Note unknown error here.";
  }
  throw;
}

Will the original exceptions get thrown from both places inside the lower frame of noteError()?

WilliamKF
  • 41,123
  • 68
  • 193
  • 295
  • 1
    Try it and see? My suspicion is that it won't even compile but I detest exceptions so don't actually know. – dash-tom-bang Aug 24 '10 at 22:43
  • 6
    @Dash, "try it and see" doesn't always yield a valid and confident answer. Maybe it's undefined behavior, and trying it merely proves that it works on your machine and nowhere else. Or, if it fails, maybe it's due to a compiler bug that failed to implement that particular aspect of the standard. – Rob Kennedy Aug 24 '10 at 22:49
  • @Rob good point, thanks. "Try it and see on every compiler you can find, and then add the Comeau online compiler to the front of that list"? :) – dash-tom-bang Aug 24 '10 at 23:01
  • @Dash: No, the only way to answer this question is to cite an authoritative source such as the standard. It is very hard to prove that no data corruption results from a particular instance of misbehavior. – Potatoswatter Aug 24 '10 at 23:32

2 Answers2

6

Your original code was fine. You caught different exception types and called a function that would log a message and rethrow. The throw statement is not required to appear directly inside the corresponding catch block. If you call one of those "note" functions and you're not currently handling an exception, though, then your program will call terminate().

Your new code is also fine. It's OK to catch everything and then call another function that rethrows to go to a more specific handler. That's the exception dispatcher idiom described in the C++ FAQ. It looks a little peculiar to rethrow the exception after the dispatching block has finished, but if that same throw statement had occurred after noteError returned (inside the original catch block) instead of where it is now, then it would be perfectly ordinary; it's demonstrated in the standard, §15.1/6.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
4

The wording in the standard (§15.1/2) is (emphasis mine):

When an exception is thrown, control is transferred to the nearest handler with a matching type (15.3); “nearest” means the handler for which the compound-statement, ctor-initializer, or function-body following the try keyword was most recently entered by the thread of control and not yet exited.

When has a try block "exited"? According to the grammar (§15/1), try blocks end with a sequence of handlers, so the block ends when the last handler ends. In other words:

try // <- start of try block
{
}
catch (whatever) // <- first handler
{
}
// ... more handlers
catch (whatever_again) // <- last handler
{
} // <- end of try block

So yes, your code is fine. When re-thrown, the nearest try block has a matching handler (namely catch (...)), so that handler is entered.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • I've extended the question in a way which I still think works, but could you please confirm that a second throw will also work. – WilliamKF Aug 25 '10 at 14:28
  • 1
    @William: As soon as you put a semicolon after `throw`. :) [This question](http://stackoverflow.com/questions/2474429/does-throw-inside-a-catch-ellipsis-rethrow-the-original-error/2474436#2474436) might be of interest. – GManNickG Aug 25 '10 at 17:12