3.5 Exceptions
When you design functions, you cannot always assume that applications will call them correctly. It may be inappropriate, for example, for a function to report an error message, return an error code, or exit from a system. To handle these types of exceptions, we use language constructs to separate error handling code from ordinary code. This approach adds uniformity to program design and makes exception handling portable.
This section introduces exceptions and provides the basics for exception handling in subsequent functions and classes. Listing 3.13 is a program to get you started.
Listing 3.13 Exception handling
// hypot.C - exceptions #include <iostream.h> #include <math.h> int main() { try { float f, g; cout << "Input sides of right triangle: "; cin >> f >> g; cout << hypot(f, g) << endl; } catch (char *msg) { // catch handler cerr << msg << endl; return 1; } return 0; } $ hypot Input sides of right triangle: 3 4 5 $ hypot Input sides of right triangle: 0 0 hypot(): sides must be nonzero $ hypot Input sides of right triangle: -2 -6 hypot(): sides must be positive values
The program prompts for two sides of a right triangle and calls hypot() to return a hypotenuse, all within a designated area of the program that detects exceptions. If either argument is zero or negative, hypot() raises an exception and a catch handler displays error messages. Let's look at each of these exception handling features separately to see how they interact with the design of hypot().
try
The keyword try designates a try block, which is an area of your program that may encounter exceptions. Typically, try blocks include calls to functions that raise exceptions so that you can detect them and decide what to do. In the following try block, for example, we call hypot() with two arguments.
try { float f, g; cout << "Input sides of right triangle: "; cin >> f >> g; cout << hypot(f, g) << endl; }
Inside the try block, hypot() either returns a value or raises an exception.
catch
The keyword catch captures exceptions from try blocks. Typically, you place catch handlers immediately after try blocks. The format of a catch handler is the same as a function prototype, so you can use catch handlers to capture built-in types and objects. With hypot(), we catch a character string exception.
catch (char *msg) { // catch handler cerr msg << endl; return 1; }
When hypot() raises an exception character string, we display it as an error message on standard error and return a nonzero status from the program. If hypot() does not raise an exception, we exit from the try block and execution resumes at the next statement following the catch handler.
throw
The keyword throw raises exceptions. Inside hypot(), we throw character strings.
float hypot(float a, float b) throw(char *) { if (a == 0 || b == 0) throw "hypot(): sides must be nonzero"; if (a < 0 || b < 0) throw "hypot(): sides must be positive values"; return sqrt(a*a + b*b); }
There is no return value from hypot() when it throws exceptions. Instead, the stack is unwound back to a catch handler that matches the type of the exception. Programs with uncaught exceptions terminate automatically.
Exception Specifications
An exception specification ia a language-supported mechanism that documents which exceptions a function may throw. The throw(char *) exception specification above, for instance, indicates that hypot() throws only character string exceptions. Exception specifications also appear in function prototypes. Here are several examples.
double calc(double a) throw(); // throws no exceptions void graph(int, int *); // throws any exception
The keyword throw appears after a function's signature and specifies which exceptions, if any, a function may throw. An empty specification (throw()) indicates no exceptions are thrown. The absence of an exception specification means a function may throw any exception. Exception specifications are particularly useful in function prototypes because they provide important type information about exceptions thrown from try blocks. A caller, for instance, can use the type from a function's exception specification in a catch handler.
Chapter 13 explores exception handling in detail.