Under which circumstances is it best to report/record errors via:
- exceptions
- returning an enum indicating success/fail
- just writing the error to a log
Yes.
So far I can think of 'just writing to a log' as preferable when the
success of a program isn't affected by the error (execution can
continue) but the error is still worthy of note.
And your unit tests should be able to simulate the situation, at the
low level.
(You do _have_ unit tests, don't you?)
A program module should have a boundary and inner logic. The boundary
is where it accepts inputs from the outside "world" - either other
modules, or data, or users. The boundary filters out bad inputs,
converts commands into OO types with the corresponding behaviors, and
then calls into the inner logic.
So the real question would be - when to prefer exceptions vs returning
a success/fail flag from a function.
At the boundary, the calling code expects rejection. It should test a
return value or an "error" field, then route errors into the view for
users to understand.
Some conditions cannot be caught at the boundary, such as a file
abruptly disappearing, or the user entering a combination of inputs
which do not work together, after analysis, or the drive filling up.
Use an exception, generally, if an error's handler appears more than
one call above the error detector. The exception is a special way to
leap from anywhere within the inner logic to the boundary.
Exception handling is a major C++ topic because it's like heavy metal
music - easy to do and hard to do well. At the very least, try to
think about how an exception can cleanly and gracefully roll all state
back until it's the same as when the user entered their last input.
Cancel pending database transactions, un-use and put away all claimed
resources, etc.
Finally, write a log if you have an internal situation that is
survivable, but represents a bug somewhere. And that means actually
_read_ that log! I will get back to you just as soon as I start
following that advice!