An exception that occurs is recorded to the calling environment by means of a throw statement; this is why we also say that an exception has been thrown.. Example: throw "Fire!"; In this
Trang 1䊐 Error Conditions
Errors that occur at program runtime can seriously interrupt the normal flow of a pro-gram Some common causes of errors are
■ division by 0, or values that are too large or small for a type
■ no memory available for dynamic allocation
■ errors on file access, for example, file not found
■ attempt to access an invalid address in main memory
■ invalid user input
Anomalies like these lead to incorrect results and may cause a computer to crash Both of these cases can have fatal effects on your application
One of the programmer’s most important tasks is to predict and handle errors You can judge a program’s quality by the way it uses error-handling techniques to counteract any potential error, although this is by no means easy to achieve
䊐 Traditional Error Handling
Traditional structured programming languages use normal syntax to handle errors:
■ errors in function calls are indicated by special return values
■ global error variables or flags are set when errors occur, and then checked again later
If a function uses its return value to indicate errors, the return value must be examined whenever the function is called, even if no error has occurred
Example: if( func()> 0 )
// Return value positive => o.k
else
// Treat errors
Error variables and flags must also be checked after every corresponding action.
In other words, you need to continually check for errors while a program is executing
If you do happen to forget to check for errors, the consequences may be fatal
Trang 2610 C H A P T E R 2 8 E X C E P T I O N H A N D L I N G
// calc_err.cpp: Defining the function calc(), // which throws exceptions
//
-class Error
{ // Infos about the error cause };
double calc( int a, int b )
{
if ( b < 0 )
throw (string)"Denominator is negative!";
if( b == 0 ) {
Error errorObj;
throw errorObj;
}
return ((double)a/b);
}
Using the throw statement
Trang 3䊐 Exception Handling Concept
C++ introduces a new approach to error handling Exception handling is based on keeping
the normal functionality of the program separate from error handling The basic idea is that errors occurring in one particular part of the program are reported to another part of
the program, known as the calling environment The calling environment performs central
error handling
An application program no longer needs to continually check for errors, because in the case of an error, control is automatically transferred to the calling environment When reporting an error, specific information on the error cause can be added This information is evaluated by the error-handling routines in the calling environment
An exception that occurs is recorded to the calling environment by means of a throw
statement; this is why we also say that an exception has been thrown.
Syntax: throw fault;
The expression faultis an exception object that is thrown to the calling environment It
can belong to any type except void
Example: throw "Fire!";
In this example, the exception object is a string that is thrown to the calling environ-ment
䊐 Exception Classes
Normally, you define your own exception classes to categorize exceptions In this case you use the throwstatement to throw an object belonging to a specific exception class
An exception class need not contain data members or methods However, the type,
which is used by the calling environment to identify the error, is important Generally, the exception class will contain members that provide more specific information on the cause of the error
In the sample program on the opposite page, the calc()function throws exceptions
in two cases, where the numerator is negative or has a value of 0 In the first case, the exception thrown is a string In the second case, the exception is an Errorexception class object Instead of creating a local exception object errorObj, a temporary object can be created:
Example: throw Error(); // It is shorter
Trang 4612 C H A P T E R 2 8 E X C E P T I O N H A N D L I N G
try {
// Exceptions thrown by this block will be // caught by the exception handlers,
// which are defined next
} catch( Type1 exc1) {
// Type1 exceptions are handled here
}
[ catch( Type2 exc2) {
// Type2 exceptions are handled here
}
//etc
] [ catch( ) {
// All other exceptions are handled here
}
The brackets [ ]in a syntax description indicate that the enclosed section is optional
✓ NOTE
Syntax of try and catch blocks
Trang 5䊐 How Exception Handling Works
The part of a program that performs central error handling in the calling environment is
referred to as an exception handler An exception handler catches the exception object
thrown to it and performs error handling The exception object type determines which handler will catch it and consequently be executed
This means that you need to specify two things when implementing exception han-dling:
■ the part of the program that can throw exceptions
■ the exception handlers that will process the various exception types
C++ provides language elements for this task, the keywords tryandcatch Each key-word precedes a code block and thus they are often referred to as tryandcatchblocks Syntactically speaking, each tryandcatchblock is a statement, however
A try block contains the program code in which errors can occur and exceptions can be
thrown Normally, a tryblock will consist of a group of functions that can produce simi-lar errors
Each catch block defines an exception handler, where the exception declaration, which is
enclosed in parentheses, defines the type of exceptions the handler can catch The catchblocks immediately follow the try block A minimum of one catchblock is required
The exception handlers defined by the catch blocks catch the exceptions thrown within the tryblock If there is no handler defined for a particular exception type, the program will not simply enter an undefined state but will be orderly terminated by a call
to the standard function terminate()
It is common practice to define specific handlers for certain types of errors and one
generic handler for all other errors This functionality is provided by a special syntax in thecatchstatement with an exception declaration consisting of just three dots
Syntax: catch( )
{ // General handler for
// all other exceptions }
Since the application program decides what reaction is applicable for certain error condi-tions, the tryandcatchblocks are formulated in the application
Trang 6614 C H A P T E R 2 8 E X C E P T I O N H A N D L I N G
// calc_err.cpp: Tests the function calc(), // which throws exceptions
//
-#include <iostream>
#include <string>
using namespace std;
double calc( int a, int b );
int main() {
int x, y;
double res;
bool flag = false;
do {
try // try block {
cout << "Enter two positive integers: ";
cin >> x >> y;
res = calc( x, y);
cout << x << "/" << y << " = " << res << endl; flag = true; // Then to leave the loop
} catch( string& s) // 1st catch block {
cerr << s << endl;
} catch( Error& ) // 2nd catch block {
cerr << "Division by 0! " << endl;
} catch( ) // 3rd catch block {
cerr << "Unexpected exception! \n";
exit(1);
}
}while( !flag);
// continued
return 0;
}
As the Errorclass contains no data members, the corresponding catchblock declares only the type
of exception, and no parameters This avoids a compiler warning since the parameter is not used
✓ NOTE
Demonstration program
Trang 7䊐 Backing Out of an Error Condition
When the throwstatement is executed, an exception object is thrown That is, a tem-porary object of the same type and content as the throwexpression is created
Example: throw "Cyclone!";
This creates a string as an exception object and copies the string "Cyclone!" to it Thus, if the throwexpression is a class type, the copy constructor is executed
The exception object is then thrown and the program control leaves the tryblock Any changes to the stack that took place after entering the try block are unwound
This specifically involves destroying any local, non-static objects Unwinding the stack
allow you to back out of the normal program flow in an orderly manner
䊐 Searching for Handlers
After leaving the tryblock, the program control is transferred to an matching handler
in the catchblocks that follow This search operation is always performed sequentially beginning with the first catch block and the exception declaration of the handler determines whether the handler should be executed
A handler is called when the type in the exception declaration is
■ identical to the exception type thrown or
■ a base class of the exception type or
■ a base class pointer and the exception is a pointer to a derived class
This is why the general exception handler catch( )always has to be defined last Since the first suitable handler will be executed, and any exception thrown will be caught by the general handler, a handler defined after the general handler would never
be called
䊐 Continuing the Program
After executing a handler, the program continues with the first statement following the catchblocks, unless the handler throws another exception or terminates the program After completing exception handling, the exception object that was thrown is destroyed The first two catchblocks handle both exceptions that the calc() function can throw In both cases a message is displayed and the program carries on prompting for input and computing values If an unexpected exception occurs, a message is again dis-played, but in this case the program then terminates
Trang 8616 C H A P T E R 2 8 E X C E P T I O N H A N D L I N G
try {
// Type1 exceptions are thrown here
try {
// Type1 and Type2 exceptions are thrown here
} catch( Type2 e2) {
// Type2 exceptions are pre-handled here throw; // and thrown again
}
// Other Type1 exceptions // can be thrown
} catch( Type1 e1) {
// Type1 exceptions are handled here
} catch( ) {
// All remaining exceptions are handled here, // particularly Type2 exceptions
}
This scenario assumes that the error classes Type1andType2are not derived one from another If classType2is derived from class Type1, any Type2exceptions thrown will be caught by the handler for the base class Type1
✓ NOTE
Nested try and catch blocks
Trang 9䊐 Nested try and catch Blocks
A program will normally contain multiple tryblocks with appropriate exception han-dlers This allows for various error handling in different parts of the program
However, a tryblock can contain additional tryblocks This allows you to use the handlers in a nested tryblock for special purpose error handling, leaving the handlers in the surrounding tryblock to deal with remaining errors Handlers in a nested tryblock can also pre-handle specific errors and then pass control to the tryblock wrapper for final handling
䊐 Re-throwing Exceptions
In the last of these cases an exception thrown by the nested tryblock has to be passed
to the try block wrapper This is achieved using a throw statement that does not expect an exception object
Example: throw; // in a catch block
This re-throws the pre-handled exception, which can then be processed by the handler
in the surrounding tryblock The statement is only valid within a nested catchblock for this reason
䊐 Exception Specifications
The exceptions that a function can throw are features of that function The application programmer must have knowledge of both the function prototype and the exceptions the function can throw to ensure that he or she will be capable of programming correct func-tion calls and taking appropriate acfunc-tion in case of errors
The exceptions a function can throw can be stated in a so-called exception specifica-tion list when you declare a funcspecifica-tion
Example: int func(int) throw(BadIndex, OutOfRange);
The list BadIndex,OutOfRange states the exceptions that the function func()can throw If the list is empty, that is, if the list contains only the throw()statement, no exceptions are thrown If the throwstatement is also missing, there is no specific infor-mation about possible exceptions and any exception can be thrown
Trang 10618 C H A P T E R 2 8 E X C E P T I O N H A N D L I N G
// calc_new.cpp: New version of function calc(), // which throws exceptions of type // MathError
//
-#include <string>
#include <iostream>
using namespace std;
class MathError
{ private:
string message;
public:
MathError( const string& s) : message(s) {}
const string& getMessage() const {return message;} };
double calc( int a, int b ) throw(MathError);
int main() {
int x, y; bool flag = false;
do {
try // try block {
cout << "Enter two positive integers: ";
cin >> x >> y;
cout << x <<"/"<< y <<" = "<< calc( x, y) << '\n'; flag = true; // To leave the loop
} catch( MathError& err) // catch block {
cerr << err.getMessage() << endl;
}
}while( !flag);
// continued
return 0;
}
double calc( int a, int b ) throw (MathError)
{ if ( b < 0 )
throw MathError("Denominator is negative!");
if( b == 0 ) throw MathError("Division by 0!");
return ((double)a/b);
}
Exception handling for numeric operations