C++ - throw vs. throw e
When rethrowing an exception in C++, there can really be a difference between throw
and throw e;
.
Prepare some classes
- these are
struct
s 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
Simple test
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:
- throw
D
- catch it as
D
- rethrow it
- catch it as
B
- call its
print
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:
It’s still 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:
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;
instead ofthrow e;
here, it would behave as expected - no type change and even no copy - if we caught
D
instead ofB
in the second (outer) catch, it would miss this catch, because the new thrown type really isB
Conclusion
About throw;
:
- rethrows an exception
- does not make a copy
- preserves type
- additionally, can be used from
catch (...)
About throw e;
:
- 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 throw;
.
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.
See also
This is explained in several posts on Stack Overflow, e.g.
Especially, this answer summarises the main points made here.
The difference between throw;
and throw e;
is explained here at cppreference.com - see the two cases in the Syntax part and their descriptions in the Explanation part.