Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
Of course, the thrown exception must end up some place. This
place is the exception handler, and you need one exception handler for every exception type you want to catch. However, polymorphism also works for
exceptions, so one exception handler can work with an exception type and
classes derived from that type.
Exception handlers immediately follow the try block
and are denoted by the keyword catch:
try {
// Code that may generate exceptions
} catch(type1 id1) {
// Handle exceptions of type1
} catch(type2 id2) {
// Handle exceptions of type2
} catch(type3 id3)
// Etc...
} catch(typeN idN)
// Handle exceptions of typeN
}
// Normal execution resumes here...
The syntax of a catch clause resembles functions that
take a single argument. The identifier (id1, id2, and so on) can
be used inside the handler, just like a function argument, although you can
omit the identifier if it s not needed in the handler. The exception type
usually gives you enough information to deal with it.
The handlers must appear directly after the try
block. If an exception is thrown, the exception-handling mechanism goes hunting
for the first handler with an argument that matches the type of the exception.
It then enters that catch clause, and the exception is considered
handled. (The search for handlers stops once the catch clause is found.)
Only the matching catch clause executes; control then resumes after the
last handler associated with that try block.
Notice that, within the try block, a number of
different function calls might generate the same type of exception, but you
need only one handler.
To illustrate try and catch, the following
variation of Nonlocal.cpp replaces the call to setjmp( )
with a try block and replaces the call to longjmp( ) with a throw
statement:
//: C01:Nonlocal2.cpp
// Illustrates exceptions.
#include <iostream>
using namespace std;
class Rainbow {
public:
Rainbow() { cout << "Rainbow()"
<< endl; }
~Rainbow() { cout << "~Rainbow()"
<< endl; }
};
void oz() {
Rainbow rb;
for(int i = 0; i < 3; i++)
cout << "there's no place like
home" << endl;
throw 47;
}
int main() {
try {
cout << "tornado, witch, munchkins..."
<< endl;
oz();
} catch(int) {
cout << "Auntie Em! I had the strangest
dream..."
<< endl;
}
} ///:~
When the throw statement in oz( )
executes, program control backtracks until it finds the catch clause
that takes an int parameter. Execution resumes with the body of that catch
clause. The most important difference between this program and Nonlocal.cpp
is that the destructor for the object rb is called when the throw
statement causes execution to leave the function oz( ).
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |