C++ - throw vs. throw e
When rethrowing an exception in C++, there can really be a difference between
Prepare some classes
- these are
structs so that everything is public - it does not matter here
- this is a simple Base-Derived example with a virtual member function printing some output so that we know which one was called
- constructors (copy and move) print output, so that we know which one is called (or if none was called)
- assignment operators (copy and move) are deleted so that we avoid any confusion
We call a function which has a parameter of type
B and we use the type
D as an argument. There is nothing interesting here, we do it only to test if the virtual function works correctly. It prints:
Of course, no copy/move constructor had been called, because we were passing by reference.
Rethrowing using throw
Here, the code takes these steps:
- catch it as
- rethrow it
- catch it as
- call its
Since it is
D, it prints:
This was expected. It is similar to calling of the
f function above.
“Rethrowing” using throw e
The only difference is that
throw; has been changed to
throw e;. It prints:
copy to D D
D, but an (unnecessary) copy has been made (via copy constructor). In fact,
throw always needs a copy constructor to be accessible. Even the previous example (with
throw only) would not work with the copy constructor deleted, because the line
throw D(); would need it - despite not really calling it due to copy elision.
“Rethrowing” D using throw e
Now, additionally, in the first catch, we are catching it as
B instead of
D. This prints:
copy to B B
Not only there is a copy, but the type had been changed entirely to the base type (we caught). So, the throwing took into account the type of the variable, not the real type of the object.
Please note that:
- if we used
throw e;here, it would behave as expected - no type change and even no copy
- if we caught
Bin the second (outer) catch, it would miss this catch, because the new thrown type really is
- rethrows an exception
- does not make a copy
- preserves type
- additionally, can be used from
- throws a new exception (to be correct, this should not be called rethrowing)
- does make a copy
- does not preserve type
So, a simple hint is to always use
Please note that the statement about not making a copy is only true when catching a reference. Catching a value of course does cause a copy of the argument value into the catch block.
This is explained in several posts on Stack Overflow, e.g.
Especially, this answer summarises the main points made here.
The difference between
throw e; is explained here at cppreference.com - see the two cases in the Syntax part and their descriptions in the Explanation part.