C H A P T E R  8

Exception Handling

This chapter discusses the C++ compiler's implementation of exception handling. Additional information can be found in Section 11.2, Using Exceptions in a Multithreaded Program. For more information on exception handling, see The C++ Programming Language, Third Edition, by Bjarne Stroustrup (Addison-Wesley, 1997).

8.1 Synchronous and Asynchronous Exceptions

Exception handling is designed to support only synchronous exceptions, such as array range checks. The term synchronous exception means that exceptions can be originated only from throw expressions.

The C++ standard supports synchronous exception handling with a termination model. Termination means that once an exception is thrown, control never returns to the throw point.

Exception handling is not designed to directly handle asynchronous exceptions such as keyboard interrupts. However, you can make exception handling work in the presence of asynchronous events if you are careful. For instance, to make exception handling work with signals, you can write a signal handler that sets a global variable, and create another routine that polls the value of that variable at regular intervals and throws an exception when the value changes. You cannot throw an exception from a signal handler.

8.2 Specifying Runtime Errors

There are five runtime error messages associated with exceptions:

When errors are detected at runtime, the error message displays the type of the current exception and one of the five error messages. By default, the predefined function terminate() is called, which then calls abort().

The compiler uses the information provided in the exception specification to optimize code production. For example, table entries for functions that do not throw exceptions are suppressed, and runtime checking for exception specifications of functions is eliminated wherever possible.

8.3 Disabling Exceptions

If you know that exceptions are not used in a program, you can use the compiler option -features=no%except to suppress generation of code that supports exception handling. The use of the option results in slightly smaller code size and faster code execution. However, when files compiled with exceptions disabled are linked to files using exceptions, some local objects in the files compiled with exceptions disabled are not destroyed when exceptions occur. By default, the compiler generates code to support exception handling. Unless the time and space overhead is important, it is usually better to leave exceptions enabled.

Note - Because the C++ standard library, dynamic_cast, and the default operator new require exceptions, you should not turn off exceptions when you compile in standard mode (the default mode).

8.4 Using Runtime Functions and Predefined Exceptions

The standard header <exception> provides the classes and exception-related functions specified in the C++ standard. You can access this header only when compiling in standard mode (compiler default mode, or with option -compat=5). The following excerpt shows the <exception> header file declarations.

// standard header <exception>
namespace std {
    class exception {
           exception() throw();
           exception(const exception&) throw();
           exception& operator=(const exception&) throw();
           virtual ~exception() throw();
           virtual const char* what() const throw();
    class bad_exception: public exception {...};
    // Unexpected exception handling
       typedef void (*unexpected_handler)();
         set_unexpected(unexpected_handler) throw();
       void unexpected();
    // Termination handling
       typedef void (*terminate_handler)();
       terminate_handler set_terminate(terminate_handler) throw();
       void terminate();
       bool uncaught_exception() throw();

The standard class exception is the base class for all exceptions thrown by selected language constructs or by the C++ standard library. An object of type exception can be constructed, copied, and destroyed without generating an exception. The virtual member function what() returns a character string that describes the exception.

For compatibility with exceptions as used in C++ release 4.2, the header <exception.h> is also provided for use in standard mode. This header allows for a transition to standard C++ code and contains declarations that are not part of standard C++. Update your code to follow the C++ standard (using <exception> instead of <exception.h>) as development schedules permit.

// header <exception.h>, used for transition
#include <exception>
#include <new>
using std::exception;
using std::bad_exception;
using std::set_unexpected;
using std::unexpected;
using std::set_terminate;
using std::terminate;
typedef std::exception xmsg;
typedef std::bad_exception xunexpected;
typedef std::bad_alloc xalloc;

In compatibility mode (--compat[=4]), header <exception> is not available, and header <exception.h> refers to the same header provided with C++ release 4.2. It is not reproduced here.

8.5 Mixing Exceptions With Signals and Setjmp/Longjmp

You can use the setjmp/longjmp functions in a program where exceptions can occur, as long as they do not interact.

All the rules for using exceptions and setjmp/longjmp separately apply. In addition, a longjmp from point A to point B is valid only if an exception thrown at A and caught at B would have the same effect. In particular, you must not longjmp into or out of a try-block or catch-block (directly or indirectly), or longjmp past the initialization or non-trivial destruction of auto variables or temporary variables.

You cannot throw an exception from a signal handler.

8.6 Building Shared Libraries That Have Exceptions

Never use -Bsymbolic with programs containing C++ code, use linker map files instead. With -Bsymbolic, references in different modules can bind to different copies of what is supposed to be one global object.

The exception mechanism relies on comparing addresses. If you have two copies of something, their addresses won't compare equal, and the exception mechanism can fail because the exception mechanism relies on comparing what are supposed to be unique addresses.

When shared libraries are opened with dlopen, you must use RTLD_GLOBAL for exceptions to work.