views:

406

answers:

5

Is Structured Exception Handling bad? What is the right way to handle exceptions?

EDIT: Exception Handling in .NET using C#.

I usually have a set of specific exception classes (DivideByZeroException, ArrayTypeMismatchException) and don't have a generic "catch (Exception ex)".

The thinking behind this is that I expect certain types of exceptions to occur and have specific actions defined when they occur and the unexpected exceptions would rise up the the interface (either windows or web). Is this a good practice?

+3  A: 

Catch statements + Stack traces. Don't ever catch an exception without printing a stack trace, you or someone else will have to checkout that code again and place stack traces in the Catch block when an error occurs and your log files are either empty or vague.

Zombies
Unless you know exactly why it's happened and how to recover, of course. There are times when that's the case, but you can't actually avoid the exception in the first place.
Jon Skeet
IOExceptions in Java being a classic example - they represent disaster from the POV of the object that generates them (a socket in an exception state is likely to be useless forever), but usually not for the app (socket connection timed out, life goes on). Hence the checked exceptions war.
Steve Jessop
+3  A: 

I'm not sure what you mean by 'structured exception handling'.

The worst thing that can be done in exception handling is to 'swallow' the exception or handle it silently.

Do NOT do this:

try {
   ...
}
catch (Exception e) {
   //TODO: handle this later
}

This is very often done out of laziness to get code to compile. If you do not know how to handle the exception at a particular level, have the method throw the exception and at least have a catch all handler at the top. Provide feedback somehow (via the GUI, a page / email to a support person, log file) so that the issue can eventually get fixed. Silently catching an exception almost always leads to a bigger issue happening later on and it being difficult to trace.

Paul Croarkin
+1  A: 

My recommendation:

Don't catch an exception unless:

  • Failure to do so would cause the application to crash (e.g. in an event handler)
    • And in this situation, be sure to log the exception so that you know what happened and when
  • You can do something to try and remedy the situation (e.g. implementing a retry mechanism when calling an external API that occasionally throws an exception (note that exception handling should not be used to control program flow))
    • And in this situation, only catch the specific exception type that you expect to get thrown

Catching the exception at the highest possible level means that you get the maximum call stack, which is very useful when you're going through the logs and trying to see what initial action triggered the sequence of events that led to the exception in the first place.

Richard Ev
+1  A: 

This is a complex topic... there are books on this... but... There are two major types of exception handling... inline, where code to deal with potential errors is inline with the code that a method or routine would "normally" execute, and structured exception handling, where the code is elsewhere, and teh infrastructure is designed to automatically switych to that exception handling code when a unexpected event (an error) occurs... Both have advantedges and disadvanteges. The "inline" approach tends to produce code which is much more cluttered (with error code) and harder to read and maintain. But it's easier to produce up front as it does not require any upfront analysis, When using inline error handling, you often see methods returning boolean or numeric "error" codes, indiocating to the caller whether the metjhod or routine was successful. This eliminates the "functional" syntax of having a routine "return" a meaningful business value or object, (since every function by convention must return an error code) When using structured exception handling, this issue is moot.

Structured exception handling, otoh, in general is harder to do well, as it requires up front analysis as to what errors a routine or method could possibly produce, and as to what the method can or should do about each error if it does occur.

One thing for sure, Do not mix the two approaches in a single component...

Charles Bretana
A: 

I'm not a Windows programmer, but it seems to me that using structured exception handling to treat hardware exceptions like software exceptions means that:

  • Your code does something that in the C++ standard produces undefined or implementation-defined behaviour (such as dividing by zero).
  • Windows defines that with SEH enabled it throws an exception in that case.
  • You are using this fact to catch the exception and/or execute a termination handler.

So the questions to ask, IMO, are:

  • Is your programming task really of a nature that standard C++ cannot handle? (or can only handle in a way which is measurably inferior to what you get by allowing the hardware exception).
  • Do you really need to take action when your code goes non-standard?
  • Can you write your code so that it doesn't provoke hardware exceptions in the first place?

If the answers are 'yes', 'yes', 'no', then structured exception handling is needed. Otherwise you may be able to avoid it, in which case you probably want to. Writing exception-safe code is tricky, so the stronger the exception guarantees you can offer the better. Code which maybe divides by zero with SEH isn't offering the nothrow guarantee, when perhaps with a bit of redesign so that callers don't give it duff data, it could do so. But if a function already has to throw exceptions for other reasons, then also possibly throwing them for hardware traps might make things no worse.

One notable special case is memory allocation. Not sure if .NET does this, but on linux allocation only fails if there's insufficient virtual address space for the allocation. Physical memory is committed on first use, and causes a hardware exception if there isn't enough. Since memory allocation is supposed to throw std::bad_alloc on failure, and the implementation fails to implement this requirement of the standard, it may be that in some cases converting the hardware exception to software is the right thing to do. However, that hardware exception can occur in unexpected places, (including in routines you thought were nothrow), so may still be impossible to handle gracefully, which is why linux core dumps instead of throwing. In practice, anything that gets initialised fully will crash its constructor, which is often close enough to the allocation that a software exception instead would be useful.

Steve Jessop