I would ask, of the try...catch
section, "does this code know how to recover from the error, or not?
Code which uses try...catch
is anticipating that an exception could happen. Reasons that you would write try...catch
at all instead of letting the exception simply pass through are:
- Add some code to make the parent function exception safe. A lot of this should be done quietly with RAII in destructors, but sometimes (e.g. a move operation) need more work to roll-back a partially completed job, it depends on the level of exception safety you want.
- Emit or add some debugging information and rethrow the exception.
- Try to recover from the error.
For cases 1 and 2 you probably don't need to worry about user exception types, they will look like this
try {
....
} catch (const std::exception & e) {
// print or tidy up or whatever
throw;
} catch (...) {
// print or tidy up or whatever
// also complain that std::exception should have been thrown
throw;
}
This will probably by 99% of real world cases, in my experience.
Sometimes you will want to recover from the error. Maybe the parent function knows that a library will fail in certain conditions which can be fixed dynamically, or there is a strategy for re-attempting a job using different mechanisms.
Sometimes the catch
block will be written specifically because the lower-level code has been designed to throw exceptions as part of its normal flow. (I often do this when reading untrusted external data, where many things can predictably go wrong.)
In these, rarer cases, user-defined types make sense.