Another slightly edited post from my old C++ blog. Again, you may have seen this one before.
This post is a quasi follow-up to the “little exception shop of horrors”_. As I mentioned in that post, I believe the reason for dumping all the exception handling code into a single header file was a misguided attempt at avoiding code duplication. No, I didn’t write that code, so I can only speculate as to why it was done. I inherited the project that contained this code and the reasons were lost in the mists of time. I did file it under “sound idea but bad execution”. It doesn’t fix the problem and you still have code duplication as the preprocessor will do the duplication work for you. Ah well, at least to don’t have to type the code in yourself multiple times. I couldn’t help but think that there must be a better way.
I more or less forgot about the whole thing as the code was about to be retired anyway. At some point I was talking to a colleague about it and he showed me a much nicer way of addressing this problem without the code duplication and in a much cleaner fashion. Start with a try/catch block like this:
try {
// ... Lots of code here
}
catch (...) {
handle_common_exceptions();
}
The handler function looks like this:
void handle_common_exceptions {
try {
throw;
}
catch (specialised_exception const &ref) {
// handling code
}
catch (another_sub_exception const &ex) {
// ... more exception handling code ..
}
catch (std::bad_alloc const &ref) {
// ... even more
}
}
The elegant part is that you rethrow the exception that has been caught in the original try block and then handle those exceptions that your code actually can handle at this point. Normally, catch (…) is only useful if you are in a piece of code which requires you to stop any exceptions from escaping. You can’t determine what the actual exception is, so you can’t handle it appropriately. The only thing you can do is to say “oops, sorry”.
Rethrowing the exception inside the catch-all handler does restore access to the exception information so you can handle the exceptions that are appropriate at the point of the catch handler. As long as you don’t add another catch-all handler inside the handler function (note that I didn’t), those exceptions that you cannot handle at this point propagate further up the call chain as they escape the handler function due to the rethrow.
Quite neat, don’t you think? Thanks to Alan Stokes for showing this technique to me.