Exceptions

			  Think, now: where would your good be if
			there were no evil, and what would the
			world look like without shadow?
 				M. Bulgakov, The Master and Margarita
Normally a function operates on some domain of arguments, to produce a result in some range. If a programmer wants the function to be robust, which should always be the case, he should provide for the ways to handle arguments that the function cannot by definition act upon. For example, consider that you have to write a function double sqrt (double x) What would be a good way to handle a negative x passed to it? One way would be to just exit the program with an error message, but that is not really robust. Another way would be to add another argument -- flag -- to the function, that would be set to TRUE on success of the operation and FALSE otherwise. But that requires having an extra variable, and is not really convenient. Plus, neither of these two ways provide for a really graceful method of handling errors -- the ability to either handle error on the spot OR pass it "up" all the way through the callers of the failed function. This can be done with exceptions.

In the case of our function (square root) the result of the execution of the function can be either the calculation and return of square root of x, if x>=0, or an exception can be raised by the function, signaling that some kind of an error occured. The exception can then be caught by the function that called sqrt and dealt with as the function wishes -- an error message can be printed, the exception can be ignored, or passed on to the caller of the caller of sqrt... isn't it beautiful?

Now if the words were a little confusing, let's look at how it's done in C++...

To use exceptions you must have a class defined for each exception. For example, supposed you have a class for an out of range error called OutOfRange. Now, in the body of your function you can check whether the argument is >=0 (we are still using sqrt as an example), and if so, return the square root. Otherwise, we raise an exception, like this

throw OutOfRange(); Easy. Now, the caller function must be written so that it can handle the exception. Here's the syntax: try { // call functions that may raise exceptions // ... } catch (exception) { // Deal with the exception // ... } Fairly easy too, isn't it?

To make the defensive programming even easier, the exceptions can have arguments, so you can deal with exceptions in the catch clause according to the arguments.

What about unhandled exceptions, the ones that are not caught? Well, the terminate() function is called, which executes the absolutely last-resort handling function that can be specified with set_terminate function, which takes a void function with no parameters. If no such last-resort function was set, the terminate() function by default calls abort().

Well, that's all there is to know about exceptions. By the way, it's a very recent addition to the language, and very few compilers support it. For example, g++ that I use (2.6.0) does not, and GNU compilers support a lot of features...


Text written for the course by Cristobal Joseevich Junta <grisha@mit.edu>