2

Does this code

try
{
    opaque_function_that_might_throw_arbitrary_exception ();
}
catch (...)
{
    throw;
}

differ in any way semantically from just calling

opaque_function_that_might_throw_arbitrary_exception ();

in C++? Are there differences between the standards?

I though both snippets would be semantically identical, but I checked with the compiler-explorer and it generates different code, even on the highest optimization level. This made me wonder if there is something I'm missing.

levzettelin
  • 2,600
  • 19
  • 32
  • Hm, I think this situation came up in a recent cppcon talk, but I'll have to check. I might have had something to do with `noexcept` or `[[noreturn]]`, and the point of termination, but I'm not sure. – Kerrek SB Dec 17 '17 at 20:21

1 Answers1

4

Yes, there is a subtle difference in one particular place. Consider this main function:

int main() {
   RAIIHandle important_resource{ /*...*/ };

   opaque_function_that_might_throw_arbitrary_exception ();
}

Is important_resource freed upon an exception being thrwon? Well, it's implementation defined. std::terminate is called, but the stack may not be unwound if an exception escapes from main. For some resources, this could spell real trouble.

Now in this case:

int main() {
   try {
     RAIIHandle important_resource{ /*...*/ };
     opaque_function_that_might_throw_arbitrary_exception ();
   }
   catch(...) {
     throw;
   }
}

std::terminate is still called. But not before a suitable handler is found for the exception. The stack must be unwound. So our important_resource is definitely freed.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Interesting. Is this only true for the main function, or is this also the case for deeper stacks? In other words, assume you are, say, 5 frames down the stack and an exception is thrown, but the compiler can "prove" that there is no handler in place and the exception will escape from main. Is it possible that then no destructors are run at all; for all objects on the 5 stack frames? – levzettelin Dec 18 '17 at 21:31
  • @TobiasBrüll - I feel my answer may have muddled the waters for. When an exception is thrown (no matter how deep), the run time starts looking for a handler that can handle it. If the lookup can't find a handler up to and including `main`, `std::terminate` will be called. And it is unspecified if the stack, all 5 frames in your case, is unwound in that particular case. The catch-all-rethrow handler forces the unwinding in main. It will in fact force the unwinding of anything bellow it, at any scope. – StoryTeller - Unslander Monica Dec 19 '17 at 05:39