Exception Handling |
4 |
![]() |
For additional information on exception handling, see The C++ Programming Language (Second Edition) by Margaret A. Ellis and Bjarne Stroustrup.
In C++, when an exception is thrown, it cannot be ignored--there must be some kind of notification or termination of the program. If no user-provided exception handler is present, the compiler provides a default mechanism to terminate the program.
Code Example 4-1 Exception Handling Example |
class Overflow {
// ...
public:
Overflow(char,double,double);
};
void f(double x)
{
// ...
throw Overflow('+',x,3.45e107);
}
int main() {
try {
// ...
f(1.2);
//...
}
catch(Overflow& oo) {
// handle exceptions of type Overflow here
}
}
The current draft supports synchronous exception handling with termination model. Termination means that once an exception is thrown, control never returns to the throw point.
The catch block handles the exception. It either rethrows the exception, branches to a label, or ends normally. If a catch block ends normally, without a throw, the flow of control passes over all subsequent catch blocks.
Whenever an exception is thrown and caught, and control is returned outside of the function that threw the exception, stack unwinding takes place. During stack unwinding, any automatic objects that were created within the scope of that function are safely destroyed via calls to their destructors.
If a try block ends without an exception, all subsequent catch blocks are ignored.
Note - An exception handler cannot return control to the source of the error by using the return statement. A return issued in this context returns from the function containing the catch block.
This declaration indicates to the caller that the function foo generates only one exception, and that it is caught by a handler of type X:
void foo(int) throw(X); |
A variation on the previous example is:
void foo(int) throw(); |
This declaration guarantees that no exception is generated by the function foo. If an exception occurs, it results in a call to the predefined function unexpected(). By default, unexpected() calls abort() to exit the program. This default behavior can be changed by calling the set_unexpected() function; see "set_terminate() and set_unexpected() Functions" on page 103.
The check for unexpected exceptions is done at program execution time, not at compile time. The compiler may, however, eliminate unnecessary checking in some simple cases.
void foo(int) throw(x); void f(int) throw(x); { foo(13); } |
The absence of an exception specification allows any exception to be thrown.
Runtime Errors
There are five runtime error messages associated with exceptions:
The class xunexpected is now defined in exception.h.
Caution - Selecting a terminate() function that does not terminate is an error.
The compiler makes use of the information provided in the exception specification in optimizing code production. For instance, table entries for functions that do not throw exceptions are suppressed, and runtime checkings for exception specifications of functions are eliminated wherever possible. Thus, declaring functions with correct exception specifications can lead to better code generation.
typedef void (*PFV)(); PFV set_terminate(PFV); |
terminate() calls the function passed as an argument to set_terminate(). The function passed in the most recent call to set_terminate() is called. The previous function passed as an argument to set_terminate() is the return value, so you can implement a stack strategy for using terminate().
set_unexpected()
You can modify the default behavior of unexpected() by calling the function set_unexpected():
typedef void (*PFV)() PFV set_unexpected(PFV); |
unexpected() calls the function passed as an argument to set_unexpected(). The function passed in the most recent call to set_unexpected() is called. The previous function passed as an argument to set_unexpected() is the return value; so you can implement a stack strategy for using unexpected().
Matching Exceptions With Handlers
A handler type T matches a throw type E if any of the following is true:
While handlers of type (X) and (X&) both match an exception of type X, the semantics are different. Using a handler with type (X) invokes the object's copy constructor and possibly truncates the object, which can happen when the exception is derived from X.
Handlers for a try block are tried in the order of their appearance. Handlers for a derived class (or a pointer to a reference to a derived class) must precede handlers for the base class to ensure that the handler for the derived class is invoked.
No other access is checked at runtime except for the matching rule described in "Matching Exceptions With Handlers" on page 104.
-noex Compiler Option
If you know that exceptions are not used, use the compiler option -noex to suppress generation of code that supports exception handling. The use of -noex results in smaller code size and faster code execution. When files compiled with -noex are linked to files compiled without -noex, some local objects are not destroyed when exceptions occur. By default, the compiler generates code to support exception handling.
New Runtime Function and Predefined Exceptions
You can use several functions related to exception handling. The header file exception.h includes the predefined exceptions xmsg and xalloc. The definitions provided in exception.h differ from those in the X3J16 Draft Working Paper.
Default new-handler() Function
When ::operator new() cannot allocate storage, it calls the currently installed new-handler function. The default new-handler function throws an xalloc exception.
Note - The old behavior was to return a null from ::operator new() when a memory request could not be satisfied. To restore the old behavior, call set_new_handler(0).
Building Shared Libraries With Exceptions
When shared libraries are opened with dlopen, RTLD_GLOBAL must be used for exceptions to work.
Using Exceptions in a Multithreaded Environment
The current exception-handling implementation is safe for multithreading--exceptions in one thread do not interfere with exceptions in other threads. However, you cannot use exceptions to communicate across threads; an exception thrown from one thread cannot be caught in another.