An exception usually signals an error. Thought it doesn’t always indicate an eror, it can also signal some particularly unusual even in your program that deserves special attention.

Exception & Errors Handling

No mater how good our program is, it always have to be able to handle possible errors. Most applications today contain some form of error handling. Unfortunately, the level and quality of error handling varies greatly. Some applications provide so much error handling that the application constantly raises alarms, even if the user provides the correct input. Other applications provide error handling that only a developer could love—the messages are replete with jargon and the data is useful only if you designed the application. Still other applications provide one-size-fits-all error handling that simply tells the user an error occurred without saying what error it was or how to fix it.

Exception handling

One of the major features in C++ is exception handling, which is a better way of thinking about and handling errors. With exception handling the following statements apply:

  1. Error-handling code is not nearly so tedious to write, and it doesn’t become mixed up with your “normal” code. You write the code you want to happen; later in a separate section you write the code to cope with the problems. If you make multiple calls to a function, you handle the errors from that function once, in one place.
  2. Errors cannot be ignored. If a function needs to send an error message to the caller of that function, it ?throws? an object representing that error out of the function. If the caller doesn?t ?catch? the error and handle it, it goes to the next enclosing dynamic scope, and so on until the error is either caught or the program terminates because there was no handler to catch that type of exception.

This article examines C?s approach to error handling (such as it is), discusses why it did not work well for C, and explains why it won?t work at all for C++. This chapter also covers try, throw, and catch, the C++ keywords that support exception handling.

Error handling in C

In most of the examples in these volumes, we use assert( ) as it was intended: for debugging during development with code that can be disabled with #define NDEBUG for the shipping product. Runtime error checking uses the require.h functions (assure( ) and require( )) developed in Chapter 9 in Volume 1. These functions are a convenient way to say, ?There?s a problem here you?ll probably want to handle with some more sophisticated code, but you don?t need to be distracted by it in this example.? The require.h functions might be enough for small programs, but for complicated products you might need to write more sophisticated error-handling code.

Error handling is quite straightforward in situations in which you know exactly what to do because you have all the necessary information in that context. Of course, you just handle the error at that point.

The problem occurs when you don?t have enough information in that context, and you need to pass the error information into a different context where that information does exist. In C, you can handle this situation using three approaches:

  1. Return error information from the function or, if the return value cannot be used this way, set a global error condition flag. (Standard C provides errno and perror( ) to support this.) As mentioned earlier, the programmer is likely to ignore the error information because tedious and obfuscating error checking must occur with each function call. In addition, returning from a function that hits an exceptional condition might not make sense.
  2. Use the little-known Standard C library signal-handling system, implemented with the signal( ) function (to determine what happens when the event occurs) and raise( ) (to generate an event). Again, this approach involves high coupling because it requires the user of any library that generates signals to understand and install the appropriate signal-handling mechanism; also in large projects the signal numbers from different libraries might clash.
  3. Use the nonlocal goto functions in the Standard C library: setjmp( ) and longjmp( ). With setjmp( ) you save a known good state in the program, and if you get into trouble, longjmp( ) will restore that state. Again, there is high coupling between the place where the state is stored and the place where the error occurs.

When considering error-handling schemes with C++, there?s an additional very critical problem: The C techniques of signals and setjmp( )/longjmp( ) do not call destructors, so objects aren?t properly cleaned up. (In fact, if longjmp( ) jumps past the end of a scope where destructors should be called, the behavior of the program is undefined.) This makes it virtually impossible to effectively recover from an exceptional condition because you?ll always leave objects behind that haven?t been cleaned up and that can no longer be accessed. The following example demonstrates this with setjmp/longjmp: