Try as you might…

I came across a corner of C++ exception handling that I had never noticed before (yes, the title is a pun), and it was interesting enough that I thought I’d share.

The issue revolves around the type of an exception after it has been re-thrown. There are two ways to re-throw an exception after it has been caught, throwing by name:
throw e;
and simply throwing the active exception:
throw;

I had assumed that they were functionally equivalent, and for most purposes they are. However, in my case I was doing the following:

  • Throwing a specific boost::exception subclass
  • Catching by boost::exception reference
  • Modifying the caught exception (appending some error_info)
  • Re-throwing by name
  • Attempting to catch the re-thrown exception by subclass type

The last step was failing: I was unable to catch the re-thrown exception by subclass type. I discovered, though, that I could catch by subclass type if I did a simple re-throw. It was as if re-throwing by name was stripping type information off of the exception.

And, in fact, that’s exactly what happens. To make a long story short, re-throwing by name constructs a new exception of the static type of the caught exception and throws that copy. This copy is in a magical, implementation-defined memory area.

For a more detailed explanation of what’s going on, check out http://cutebugs.net/files/cpp/ar01s02.html#ftn.id2873363 and http://stackoverflow.com/questions/2360597/c-exceptions-questions-on-rethrow-of-original-exception.

Finally, here’s a bit of code showing the issue. Modifying the argument to try_() will change the re-throw method, and, at least on the compilers I’ve tried (g++-4-somethings on linux), you either catch by Subtype (expected) or Exception (not expected):


#include <exception>
#include <iostream>

using namespace std;

class Exception : public exception {};

class Subtype : public Exception {};

void try_(bool cause_unexpected)
{
    try { throw Subtype(); }
    catch (const Exception& e) {
        if (cause_unexpected)
            throw e;
        else
            throw;
    }
}

int main(void)
{
    try { try_(false); }
    catch (const Subtype&) {
        cout << "expected" << endl;
    }
    catch (const Exception&) {
        cout << "not expected" << endl;
    }

    return 0;
}
Advertisements

,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: