Here I am writing some data-centric code. Tum tum tiddle ... oh dear, this call might fail. Now if I'm living in an enterprise world like the one described in DnaVsOo, I have a choice. I can throw an exception, or I can SetAbort. The two seem to overlap - when do I do one, and when do I do the other?
Call SetAbort if the call failing will invalidate the transaction you're participating in. Use your normal judgement regarding whether or not to throw an exception.
This divide seems to run deep. Components generally SetAbort. Library objects generally throw exceptions. "Use your normal judgement" might work for my code, but what do I do about the code I use - how do I account for the fact that sometimes it'll pre-empt my exception-handling, and sometimes it won't? Or that maintenance programmers might change that without being aware of my code's usage?
Another approach is to use the CommandPattern to encapsulate a transactional unit of work and to execute the command wrapped in an exception handler. The exception handler can handle an exception by performing a SetAbort if necessary. This can simplify the flow of control (i.e. no need to return a status code that SetAbort has been performed.) Commands that can recover from some kinds of exceptions may intercede with their own handlers that retry the command when possible. -- PatrickLogan
JohnVlissides and RichardHelm wrote up a transactional CompoundCommandPattern in a recent CppReport that does much of that. (http://www.research.ibm.com/designpatterns/pubs/ph-apr99.pdf) BTW, if you squint your eyes so that everything you see gets a little fuzzy, JavaUnit and CppUnit HaveThisPattern. Tests aren't exactly transactional, but much of the structure in that CompoundCommandPattern is in the TestingFramework.