Always catch exceptions by reference

Some code I am responsible for at work recently got exposed to a new environment, and suddenly started logging exceptions. After some investigation, my colleague Thomas and I felt pretty sure what was going on, except the exception we saw in the logs was of a different type than the one that was thrown by the suspected culprit. What was going on, could the error be some place else after all? Then we looked at some intermediate code in the call hierarchy, and found the following (as usual, simplified) code :

class Exception{};
class SpecialException : public Exception {};

try {
    throw SpecialException();
} catch (Exception e) {
    cout << "Caught" << typeid(e).name() << endl;

Spot the problem? catch (Exception e) results in slicing. We are catching by value, which results in copying the exception. But since we are catching Exception, not SpecialException, Exception‘s copy construcor is called, and we lose the SpecialException part of the object. Here is an illustration of the Exception copy constructor in action:

Exception copy constructor slices away the SpecialException part of the object

On the left side is the full SpecialException object, with its Exception part shown in green. The green line illustrates the copy constructor, which only lets the Exception part of the object throuh.

The right way to write this would be catch (const Exception& e), which would result in a reference to the original SpecialException. Thanks to polymorphism, this program will now print “Caught SpecialException”, whereas the original example prints “Caught Exception”.

As a side note, always throw by value, not by pointer. That is, do throw Exception();, not throw new Exception();. After all, you want to be throwing an exception, not a pointer. And as always, there is no point in allocating on the heap if you don’t have to. Requiring people to clean up memory for you when catching is not very polite.

13 thoughts on “Always catch exceptions by reference

  1. Hey, great explanation! thanks!
    I was wondering – is there a reason not to use a const Exception& e?
    Is there a scenario we might modify the data of the thrown exception, so it better not be const?

      1. Have you ever thought of modifying an exception before rethrowing it? Perhaps if the caller can only partially handle the error and you want it to continue propagating up the stack.

          1. Honestly I probably would create a new one too, though I wonder if modifying and rethrowing, or the compiler reusing the memory of the old one (considering it to be something similar to an xvalue) would be more efficient.

            1. I guess you could modify the existing exception in place and rethrow that. Then you would avoid the cost of destroying the existing exception, creating a new temporary one, and copying the temporary into the special exception memory. But the cost of that is probably negligible unless you’re using exceptions way too much in the first place.

  2. How does catching by const reference handle scope? You appear to have a reference to a stack variable that just died when the function threw..

Leave a Reply

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

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

Facebook photo

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

Connecting to %s