I am refactoring an old code, and one of the things I’d like to address is the way that errors are handled. I’m well aware of exceptions and how they work, but I’m not entirely sure they’re the best solution for the situations I’m trying to handle.
In this code, if things don’t validate, there’s really no reason or advantage to unwind the stack. We’re done. There’s no point in trying to save the ship, because it’s a non-interactive code that runs in parallel through the Sun Grid Engine. The user can’t intervene. What’s more, these validation failures don’t really represent exceptional circumstances. They’re expected.
So how do I best deal with this? One thing I’m not sure I want is an exit point in every class method that can fail. That seems unmaintainable. Am I wrong? Is it acceptable practice to just call exit() or abort() at the failure point in codes like this? Or should I throw an exception all the way back to some generic catch statement in main? What’s the advantage?
Throwing an exception to be caught in main and then exiting means your RAII resource objects get cleaned up. On most systems this isn’t needed for a lot of resource types. The OS will clean up memory, file handles, etc. (though I’ve used a system where failing to free memory meant it remained allocated until system restart, so leaking on program exit wasn’t a good idea.)
But there are other resource types that you may want to release cleanly such as network or database connections, or a mechanical device you’re driving and need to shut down safely. If an application uses a lot of such things then you may prefer to throw an exception to unwind the stack back to main, and then exit.
So the appropriate method of exiting depends on the application. If an application knows it’s safe then calling _Exit(), abort(), exit(), or quickexit() may be perfectly reasonable. (Library code shouldn’t call these, since obviously the library has no idea whether its safe for every application that will ever use the library.) If there is some critical clean up that must be performed before an application exits but you know it’s limited, then the application can register that clean up code via atexit() or at_quick_exit().
So basically decide what you need cleaned up, document it, implement it, and try to make sure it’s tested.