Catching an Exception
We catch exception objects by their type using one or a series of catch clauses. A catch clause consists of three parts: the keyword catch, the declaration of a single type or single object within parentheses, and a set of statements within curly braces that does the actual handling of the exception. For example, consider the following set of catch clauses:
// defined elsewhere ...
extern void log_message( const char* );
extern string err_messages[];
exterm ostream log_file;
bool some_function()
{
bool status = true;
// ... we'll get to this part!
catch( int errno ){
log_message( err_messages[ errno] );
status = false;
}
catch( const char *str ){
log_message( str );
status = false;
}
catch( iterator_overflow &iof ){
iof.what_happened( log_file );
status = false;
}
// last line of function
return status;
}
The following catch clauses handle the three exception objects we threw in the preceding section:
throw 42;
throw "panic: no buffer!";
throw iterator_overflow( _index, Triangular::_max_elems );
The type of the exception object is compared against the exception declaration of each catch clause in turn. If the types match, the body of the catch clause is executed. For example, when we throw our iterator_overflow object, the three catch clauses are examined in turn. The exception declaration of the third clause matches the type of the exception object, and the associated statements are executed. The what_happened() member function of our exception class is invoked through iof, the exception object. The const char* return value is passed to some external log_message() function. Following that, status is set to false.
This represents a complete handling of the exception. Normal program execution resumes at the first program statement following the set of catch clauses. In our example, normal program execution begins again with the return of status.
What happens with the throw of the string literal? The matching catch clause this time is the second instance. log_message() is invoked with the str exception object as its argument. status is set to false. Again, the exception is now handled. Control flows past the third catch clause, and normal program execution begins again with the return of status.
It may be that we cannot completely handle an exception. After having logged the message, we might need to rethrow the exception for further handling elsewhere in another catch clause:
catch( iterator_overflow &iof )
{
log_message( iof.what_happened() );
// rethrow for another catch clause to handle
throw;
}
A rethrow expression consists only of the throw keyword. It can occur only within a catch clause. It rethrows the exception object, and the search for a matching catch clause continues.
A catch-all handler allows us to match every exception type. In place of the exception declaration, we specify an ellipsis. For example,
// matches all exceptions
catch( ... )
{
log_message( "exception of unknown type" );
// clean up and exit ...
}
We catch exception objects by their type using one or a series of catch clauses. A catch clause consists of three parts: the keyword catch, the declaration of a single type or single object within parentheses, and a set of statements within curly braces that does the actual handling of the exception. For example, consider the following set of catch clauses:
// defined elsewhere ...
extern void log_message( const char* );
extern string err_messages[];
exterm ostream log_file;
bool some_function()
{
bool status = true;
// ... we'll get to this part!
catch( int errno ){
log_message( err_messages[ errno] );
status = false;
}
catch( const char *str ){
log_message( str );
status = false;
}
catch( iterator_overflow &iof ){
iof.what_happened( log_file );
status = false;
}
// last line of function
return status;
}
The following catch clauses handle the three exception objects we threw in the preceding section:
throw 42;
throw "panic: no buffer!";
throw iterator_overflow( _index, Triangular::_max_elems );
The type of the exception object is compared against the exception declaration of each catch clause in turn. If the types match, the body of the catch clause is executed. For example, when we throw our iterator_overflow object, the three catch clauses are examined in turn. The exception declaration of the third clause matches the type of the exception object, and the associated statements are executed. The what_happened() member function of our exception class is invoked through iof, the exception object. The const char* return value is passed to some external log_message() function. Following that, status is set to false.
This represents a complete handling of the exception. Normal program execution resumes at the first program statement following the set of catch clauses. In our example, normal program execution begins again with the return of status.
What happens with the throw of the string literal? The matching catch clause this time is the second instance. log_message() is invoked with the str exception object as its argument. status is set to false. Again, the exception is now handled. Control flows past the third catch clause, and normal program execution begins again with the return of status.
It may be that we cannot completely handle an exception. After having logged the message, we might need to rethrow the exception for further handling elsewhere in another catch clause:
catch( iterator_overflow &iof )
{
log_message( iof.what_happened() );
// rethrow for another catch clause to handle
throw;
}
A rethrow expression consists only of the throw keyword. It can occur only within a catch clause. It rethrows the exception object, and the search for a matching catch clause continues.
A catch-all handler allows us to match every exception type. In place of the exception declaration, we specify an ellipsis. For example,
// matches all exceptions
catch( ... )
{
log_message( "exception of unknown type" );
// clean up and exit ...
}
0 comments:
Post a Comment