A Complete Guide to Programming in C++ part 64 pot

10 119 0
A Complete Guide to Programming in C++ part 64 pot

Đang tải... (xem toàn văn)

Thông tin tài liệu

TRADITIONAL ERROR HANDLING ■ 609 ᮀ 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. 610 ■ CHAPTER 28 EXCEPTION HANDLING // 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); } ■ EXCEPTION HANDLING Using the throw statement EXCEPTION HANDLING ■ 611 ᮀ 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. ᮀ The throw Statement 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 fault is 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 throw statement 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 Error exception class object. Instead of creating a local exception object errorObj, a temporary object can be created: Example: throw Error(); // It is shorter 612 ■ CHAPTER 28 EXCEPTION HANDLING 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 ■ EXCEPTION HANDLERS Syntax of try and catch blocks EXCEPTION HANDLERS ■ 613 ᮀ 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 try and catch. Each key- word precedes a code block and thus they are often referred to as try and catch blocks. Syntactically speaking, each try and catch block is a statement, however. ᮀ try and catch Blocks A try block contains the program code in which errors can occur and exceptions can be thrown. Normally, a try block 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 catch blocks immediately follow the try block. A minimum of one catch block is required. The exception handlers defined by the catch blocks catch the exceptions thrown within the try block. 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 the catch statement 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 try and catch blocks are formulated in the application. 614 ■ CHAPTER 28 EXCEPTION HANDLING // 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 Error class contains no data members, the corresponding catch block declares only the type of exception, and no parameters. This avoids a compiler warning since the parameter is not used. ✓ NOTE ■ THROWING AND CATCHING EXCEPTIONS Demonstration program THROWING AND CATCHING EXCEPTIONS ■ 615 ᮀ Backing Out of an Error Condition When the throw statement is executed, an exception object is thrown. That is, a tem- porary object of the same type and content as the throw expression is created. Example: throw "Cyclone!"; This creates a string as an exception object and copies the string "Cyclone!" to it. Thus, if the throw expression is a class type, the copy constructor is executed. The exception object is then thrown and the program control leaves the try block. 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 try block, the program control is transferred to an matching handler in the catch blocks 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 catch blocks, 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 catch blocks 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. 616 ■ CHAPTER 28 EXCEPTION HANDLING 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 Type1 and Type2 are not derived one from another. If class Type2 is derived from class Type1, any Type2 exceptions thrown will be caught by the handler for the base class Type1. ✓ NOTE ■ NESTING EXCEPTION HANDLING Nested try and catch blocks NESTING EXCEPTION HANDLING ■ 617 ᮀ Nested try and catch Blocks A program will normally contain multiple try blocks with appropriate exception han- dlers. This allows for various error handling in different parts of the program. However, a try block can contain additional try blocks. This allows you to use the handlers in a nested try block for special purpose error handling, leaving the handlers in the surrounding try block to deal with remaining errors. Handlers in a nested try block can also pre-handle specific errors and then pass control to the try block wrapper for final handling. ᮀ Re-throwing Exceptions In the last of these cases an exception thrown by the nested try block 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 try block. The statement is only valid within a nested catch block 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 action 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 function. 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 throw statement is also missing, there is no specific infor- mation about possible exceptions and any exception can be thrown. 618 ■ CHAPTER 28 EXCEPTION HANDLING // 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); } ■ DEFINING YOUR OWN ERROR CLASSES Exception handling for numeric operations . 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. 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 ■. 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

Ngày đăng: 06/07/2014, 17:21

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan