Error handling
E.15
Throw by value, catch exceptions from a hierarchy by reference
Reason
Throwing by value (not by pointer) and catching by reference prevents copying, especially slicing base subobjects.
Example; bad
void f()
{
try {
// ...
throw new widget{}; // don't: throw by value, not by raw pointer
// ...
}
catch (base_class e) { // don't: might slice
// ...
}
}
Instead, use a reference:
catch (base_class& e) { /* ... */ }
or - typically better still - a const reference:
catch (const base_class& e) { /* ... */ }
Most handlers do not modify their exception and in general we recommend use of const.
Note
Catch by value can be appropriate for a small value type such as an enum value.
Note
To rethrow a caught exception use throw; not throw e;. Using throw e; would throw a new copy of e (sliced to the static type std::exception, when the exception is caught by catch (const std::exception& e)) instead of rethrowing the original exception of type std::runtime_error. (But keep Don't try to catch every exception in every function and Minimize the use of explicit try/catch in mind.)
Enforcement
- Flag catching by value of a type that has a virtual function.
- Flag throwing raw pointers.