Imagine two similar pieces of code:
try {
[...]
} catch (myErr &err) {
err.append(\"More info added to error...\");
throw err;
}
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.