Depending on how you have arranged your exception hierarchy, re-throwing an exception by naming the exception variable in the throw statement may slice the original exception object.
A no-argument throw expression will throw the current exception object preserving its dynamic type, whereas a throw expression with an argument will throw a new exception based on the static type of the argument to throw
.
E.g.
int main()
{
try
{
try
{
throw Derived();
}
catch (Base& b)
{
std::cout << "Caught a reference to base\n";
b.print(std::cout);
throw b;
}
}
catch (Base& b)
{
std::cout << "Caught a reference to base\n";
b.print(std::cout);
}
return 0;
}
As written above, the program will output:
Caught a reference to base
Derived
Caught a reference to base
Base
If the throw b
is replace with a throw
, then the outer catch will also catch the originally thrown Derived
exception. This still holds if the inner class catches the Base
exception by value instead of by reference - although naturally this would mean that the original exception object cannot be modified, so any changes to b
would not be reflected in the Derived
exception caught by the outer block.