Exeception Handling Best Practice

Started by
6 comments, last by SnotBob 15 years, 11 months ago
Here is newbie question. When should one use expection handling? When is it OK to simply do a check and return an error code. int DoSomething(CSomeClass *pClass) { int Error; if(!pClass) { //do somethig Error = 0; } else { Error = -456565; } return(Error); } Or void DoSomething(CSomeClass *pClass) { assert(!pClass) { //do somethig } return; } What is the best practice?
Advertisement
It's kind of tough to call. Exceptions, as the name suggests, are supposed to signal 'exceptional' circumstances. If it is reasonable to expect something to fail, then an exception's not a great plan and you should use an error code instead. However, if - in a good codebase, where everything is being done correctly, the system is assumed to have been appropriately configured, etc - you encounter a situation that's really unlikely to happen, something that challenges the assumptions you're making, then an exception is probably warranted.

Assertions generally fall into the second case, though I think you may want to pop up a dialog or something first that gives the developer an opportunity to break to the debugger (DebugBreak(), or __asm int 3;) and examine the reasons for the assertion having failed. If that dialog is dismissed or not present and the code can't continue then throwing an appropriate exception in many cases would seem fine to me.

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

A general comment is that I generally find exceptions more useful for debugging rather than recovery.

So, as superpig said, if it's something can be expected to be typical and is-not-an-error, then by all means, it's probably a bad candidate for an exception. A simple example is reading a file and finding the end of the file. Every file will have an end of file, so an exception should not be used in this circumstance. Some not-so-well-respected IO systems that I can think of have used exceptions for this, but it really damaged the design, IMHO.

So, taking the converse, it's a good candidate for an exception if the error is something pretty bad, like the graphics system failed to initialize. Of course, there are also borderline cases where some clients might want an exception (fatal in their case) and some wouldn't. In these cases, I throw an exception, but have given another method to do a check first.

As a general semantic idea, to me if you do a check, you're asking for the state of something and thus it's not an exception. However, if you're saying perform an operation, and it's unable to, then often those are exceptions. So, let's say something like this:

// No exception for this one, since we're askingbool checkIfAbleToInitializeGraphicsSystem();// Definitely an exception for this one, since we're telling and it failedIGraphicsSystem* initalizeGraphicsSystem();


That's the way I've done it in the past. I know most people worry about overuse of exceptions, and this is a valid concern. Personally I worry about underuse. You will often find that use of exceptions can make code cleaner, as long as you document the methods that have the potential to throw an exception.
You should use assertions when the condition being tested should never occur and your program won't be able to handle it. I.e. running into an assertion should be a bug.

As to throwing exceptions vs. error values, quite frankly I think that Stroustrup is wrong on this one. Exceptions are for exceptional situations, but errors needn't be the only kind of exceptions. I'm not zealously advocating abandoning all error values. I think that it's reasonable to return NULL in some instances, for example. But I do think that the way exceptions can be used to decouple exception handling from the ordinary cases does have its uses in exceptional but non-erroneous cases.

A good example is file handling. If I'm reading some data from a file and any read failure or data corruption is handled the same way by canceling the whole operation, it's bothersome to propagate error values up through all the subroutines.
Thanks for all the suggestions. Cool.
Quote:Original post by SnotBob
As to throwing exceptions vs. error values, quite frankly I think that Stroustrup is wrong on this one. Exceptions are for exceptional situations, but errors needn't be the only kind of exceptions. I'm not zealously advocating abandoning all error values. I think that it's reasonable to return NULL in some instances, for example. But I do think that the way exceptions can be used to decouple exception handling from the ordinary cases does have its uses in exceptional but non-erroneous cases.

A good example is file handling. If I'm reading some data from a file and any read failure or data corruption is handled the same way by canceling the whole operation, it's bothersome to propagate error values up through all the subroutines.


I agree with you, but I think the main reason I do is that I use exception objects. An exception object can contain *much* more helpful information than an integer error code.

After an application has shipped it's not that big of a deal - to the user, error handling is error handling. The benefit of easy to understand exceptions during development and debugging is HUGE.

There's also the question of closed APIs that you're not 100% familiar with - if an API function's only return value is an error code, you could accidentally forget to check the success code. It's possible that your code could happily continue running even if that function actually failed, and crash much later somewhere else. If the function uses exceptions instead and you don't handle the error, the exception gives you an immediate and rude awakening at the exact location of the problem.

Exceptions assist those of us who aren't 100% perfect programmers all the time with fixing our mistakes more easily.
Quote:Original post by SnotBob
You should use assertions when the condition being tested should never occur and your program won't be able to handle it. I.e. running into an assertion should be a bug.


I agree with vigorous use of assertions, especially to test preconditions. However, if it's a situation that will cause your program to wind up in a nasty state or crash, it still needs to be handled somewhere in the code. Oftentimes bugs happen in the real world that rarely happen in a debug environment. That's my only caveat to assertions, is that I sometimes seem them used in place of actual handling code and the reality is that they don't handle errors.
Quote:Original post by Rydinare
However, if it's a situation that will cause your program to wind up in a nasty state or crash, it still needs to be handled somewhere in the code.

This is actually a very good point. While an assertion macro can be set to produce debugging information and a pop-up error message to the user, there can still be plenty that can be done in an exception handler to save any data that the user might care to keep. In fact, it may sometimes be a good idea to redefine assert to throw an exception.

This topic is closed to new replies.

Advertisement