Exceptions are used over return codes/errnos to handle errors, as they are the idiomatic error handling mechanism in modern C++ code.
- First and foremost, an uncaught exception exits the program. This is a Good Thing™. Exceptions should only be thrown in the first place when an problem occurs that cannot be handled in the current scope. If this problem is not handled at some scope above the current one, the program should exit, regardless of what error handling paradigm is being used. When using error codes, you can forget to check the returning code. If this occurs, the program hobbles along in some undefined zombie state until it crashes or misbehaves some number of calls down the road, producing the same result but giving you a debugging nightmare.
- Not using error codes allows you to actually use the return value to return the output of the called function instead of using "output" parameters by passing pointers or references. This produces arguably cleaner code.
- Some places, such as constructors, cannot return error codes.
Trying to shoehorn an error code into a constructor means
- You have to use an "output" parameter to return the error code (ew).
- Your class can exist in some zombie state if the constructor fails.
Compare this to using exceptions, where a
throw
in the constructor means the object never existed in the first place. - Having a two-phase init where the constructor does little to nothing
and initialization is handled by an
init()
function returns you to point 2. (You can now be in a zombie "declared but uninitialized" state.)
- Exceptions avoid cluttering up your logic with constant checks
to see if functions succeeded.
In a way it is a separation of concerns: logic goes in the
try
block and error handling goes in thecatch
block. - Modern exception implementations are extremely cheap in performance cost, and in some cases even free until an exception is thrown. Checking error codes of every call is not free either, so performance-based arguments against exceptions are anachronisms.
- A common criticism of exceptions is that they allow functions to exit
at arbitrary points instead of just at provided
return
statements. If RAII is being properly used, this point is moot. Destructors will automatically clean up any local resources as the call stack unwinds.
The only time exceptions are not appropriate is on hard-real-time systems like avionics software where the time taken to throw and catch an exception cannot be guaranteed (see Stroustrup's page).