Exception Handling - City University of New York · CSC 330 3 An Exception is… An unusual, often...

Preview:

Citation preview

1CSC 330

CSC 330 Object-Oriented Programming

Exception HandlingException Handling

2CSC 330

C++ Exception Handling

Topics

• Exception Handling• C++ Exception Handling Basics• Throwing and Catching Exceptions• Constructors, Destructors and Exceptions

3CSC 330

An Exception is…

An unusual, often unpredictable event, detectable by software or hardware, that requires special processing; also, in C++, a variable or class object that represents an exceptional event.

An exception handler is a section of program code that is executed when a particular exception occurs.

4CSC 330

AssertionsAssertions

5CSC 330

Program Segment Example

6CSC 330

When to use assert

▪ Catching the program logic errors. Use assertion statements to catch logic errors. You can set an assertion on a condition that must be true according to your program logic. The assertion only has an effect if a logic error occurs.

▪ Checking the results of an operation. Use assertion statements to check the result of an operation. Assertions are most valuable for testing operations which results are not so obvious from a quickvisual inspection.

▪ Testing the error conditions that supposed to be handled. Use assertions to test for error conditions at a point in your code where errors supposed to be handled.

7CSC 330

Exception Handling Basics

• Exception handling is for situations where the function that detects the error cannot deal with it

• Such a function will throw an exception, and “hope” there is an exception handler to catch it

• There is no guarantee that the exception will be caught

• If it’s not caught the program terminates

8CSC 330

...Exception Handling Basics

• Exceptions are thrown and caught using try and catch blocks

try {...

}catch {

...}

• Code in the try block can throw an exception• The catch blocks contains handlers for the

various exceptions• When an exception is thrown in the try block, the

catch blocks are searched for an appropriate exception handler

9CSC 330

SyntaxSyntax

The try-block:try{compound-statement handler-list

handler-list hereThe throw-expression:throw expression

}{The handler:catch (exception-declaration) compound-statement

exception-declaration:type-specifier-list here

}

10CSC 330

Exception-Handling Overview

• Throw point– Location in try block where exception occurred– If exception handled

» Program skips remainder of try block» Resumes after catch blocks

– If not handled» Function terminates» Looks for enclosing catch block

• If no exception– Program skips catch blocks

11CSC 330

Execution of try-catch

Nostatements throw

an exception

Statement following entire try-catch

statement

Astatement throws

an exception

ExceptionHandler

Statements to deal with exception are executed

Control moves directly to exception handler

12CSC 330

Simple Exception-Handling Example: Divide by Zero

• Keyword throw– Throws an exception

» Use when error occurs– Can throw almost anything (exception object, integer, etc.)

» throw myObject;» throw 5;

• Exception objects– Base class exception ( <exception> )– Constructor can take a string (to describe exception)– Member function what() returns that string

13CSC 330

Creating an error object to throw

#include <iostream>using namespace std;

class DivideByZeroError {public:

DivideByZeroError() : message("Divide by Zero") {}void printMessage() const {cout << message;}

private:const char* message;

};

int main(){DivideByZeroError err;err.printMessage();return 0;

}

Divide by Zero

14CSC 330

Divide Function that throws an exception

#include <iostream>using namespace std;

float quotient(int numerator, int denominator) {if (denominator == 0)

throw DivideByZeroError();return (float) numerator / denominator;

}

int main(){int i = 10, j = 3;cout << quotient(i,j) << “\n”;return 0;

}

3.33333

15CSC 330

Execution Generating an Error (without try block)

#include <iostream.h>

float quotient(int numerator, int denominator) {if (denominator == 0)

throw DivideByZeroError();return (float) numerator / denominator;

}

main(){int i = 10, j = 0;cout << quotient(i,j);return 0;

}

TESTPROG.EXEPROGRAM ABORTED

OK

16CSC 330

Simple Exception-Handling Example: Divide by Zero

• Next example– Handle divide-by-zero errors– Define new exception class

» DivideByZeroException

» Inherit from exception– In division function

» Test denominator» If zero, throw exception (throw object)

– In try block» Attempt to divide» Have enclosing catch block

• Catch DivideByZeroException objects

© 2003 Prentice Hall, Inc.All rights reserved.

Outline

fig13_01.cpp(1 of 3)

1 // Fig. 13.1: fig13_01.cpp2 // A simple exception-handling example that checks for3 // divide-by-zero exceptions.4 #include <iostream>

5 6 using std::cout;7 using std::cin;8 using std::endl;

9 10 #include <exception>

11 12 using std::exception;

13 14 // DivideByZeroException objects should be thrown by functions15 // upon detecting division-by-zero exceptions 16 class DivideByZeroException : public exception { 17 18 public:19 20 // constructor specifies default error message 21 DivideByZeroException::DivideByZeroException() 22 : exception( "attempted to divide by zero" ) {} 23 24 }; // end class DivideByZeroException25

Define new exception class (inherit from exception). Pass a descriptive message to the constructor.

© 2003 Prentice Hall, Inc.All rights reserved.

Outline

fig13_01.cpp(2 of 3)

26 // perform division and throw DivideByZeroException object if 27 // divide-by-zero exception occurs28 double quotient( int numerator, int denominator )29 {30 // throw DivideByZeroException if trying to divide by zero31 if ( denominator == 0 )32 throw DivideByZeroException(); // terminate function

33 34 // return division result35 return static_cast< double >( numerator ) / denominator;

36 37 } // end function quotient38 39 int main()40 {41 int number1; // user-specified numerator42 int number2; // user-specified denominator43 double result; // result of division

44 45 cout << "Enter two integers (end-of-file to end): ";

46

If the denominator is zero, throwa DivideByZeroExceptionobject.

© 2003 Prentice Hall, Inc.All rights reserved.

Outline

fig13_01.cpp(3 of 3)

47 // enable user to enter two integers to divide48 while ( cin >> number1 >> number2 ) {49 50 // try block contains code that might throw exception 51 // and code that should not execute if an exception occurs52 try { 53 result = quotient( number1, number2 ); 54 cout << "The quotient is: " << result << endl; 55 56 } // end try 57 58 // exception handler handles a divide-by-zero exception 59 catch ( DivideByZeroException &divideByZeroException ) { 60 cout << "Exception occurred: "61 << divideByZeroException.what() << endl; 62 63 } // end catch

64 65 cout << "\nEnter two integers (end-of-file to end): ";

66 67 } // end while

68 69 cout << endl;

70 71 return 0; // terminate normally

72 73 } // end main

Notice the structure of the tryand catch blocks. The catchblock can catch DivideByZeroExceptionobjects, and print an error message. If no exception occurs, the catch block is skipped.

Member function what returns the string describing the exception.

© 2003 Prentice Hall, Inc.All rights reserved.

Outline

fig13_01.cppoutput (1 of 1)

Enter two integers (end-of-file to end): 100 7The quotient is: 14.2857

Enter two integers (end-of-file to end): 100 0Exception occurred: attempted to divide by zero

Enter two integers (end-of-file to end): ^Z

21CSC 330

Executing Code in a try block

int main(){cout << "Enter numerator and denominator: ";int numerator, denominator;cin >> numerator >> denominator;try {

float answer = quotient(numerator, denominator);cout << "\n" << numerator << "/"

<< denominator << " = " << answer;}catch (DivideByZeroError error) { //error handler

cout << "ERROR: ";error.printMessage();cout << endl;return 1; //terminate because of error

}return 0; //terminate normally

}Enter numerator and denominator: 3 4

3/4 = 0.75

22CSC 330

...Executing Code in a try block

main(){cout << "Enter numerator and denominator: ";int numerator, denominator;cin >> numerator >> denominator;try {

float answer = quotient(numerator, denominator);cout << "\n" << numerator << "/"

<< denominator << " = " << answer;}catch (DivideByZeroError error) { //error handler

cout << "ERROR: ";error.printMessage();cout << endl;return 1; //terminate because of error

}return 0; //terminate normally

}

Enter numerator and denominator: 3 0ERROR: Divide by Zero

23CSC 330

Throwing an Exception

• When a program encounters an error it throws an exception using throw anObject

• anObject can be any type of object and is called the “exception object”

• Exception will be caught by the closest exception handler (for the try block from which the exception was thrown) which matches the exception object type

• A temporary copy of the exception object is created and initialized, which in turn initializes the parameter in the exception handler

• The temporary object is destroyed when the exception handler completes execution

24CSC 330

...Throwing an Exception

class DivideByZeroError {public:

DivideByZeroError() : message("Divide by Zero"){cout << "construct: DivByZeroObject\n"; }

~DivideByZeroError(){cout << "delete: DivByZeroObject\n";}

void printMessage() const {cout << message;}private:

const char* message;};

Enter numerator and denominator: 3 0construct: DivByZeroObjectdelete: DivByZeroObjectERROR: Divide by Zerodelete: DivByZeroObjectdelete: DivByZeroObject

25CSC 330

Constructors, Destructors and Exception Handling

• Error in constructor– new fails; cannot allocate memory– Cannot return a value - how to inform user?

» Hope user examines object, notices errors» Set some global variable

– Good alternative: throw an exception» Destructors automatically called for member objects» Called for automatic variables in try block

• Can catch exceptions in destructor

26CSC 330

Executing Code in a try block

main(){cout << "Enter numerator and denominator: ";int numerator, denominator;cin >> numerator >> denominator;try {

float answer = quotient(numerator, denominator);cout << "\n" << numerator << "/"

<< denominator << " = " << answer;}catch (DivideByZeroError error) { //error handler

cout << "ERROR: ";error.printMessage();cout << endl;return 1; //terminate because of error

}return 0;

}Enter numerator and denominator: 3 0construct: DivByZeroObjectdelete: DivByZeroObjectERROR: Divide by Zerodelete: DivByZeroObjectdelete: DivByZeroObject

27CSC 330

…Throwing an Exception

• Control exits the current try block and goes to appropriate catch handler

• The try blocks or functions which throw the exception can be deeply nested

• An exception can be thrown by code indirectly referenced from within a try block

• An exception terminates the block in which the exception occurred, and may cause program termination

28CSC 330

Catching an Exception

• Exception handlers are contained within catchblocks

catch(exception_object) { //exception handler code}

• Catch handler specifies the type of object that it catches

• Exceptions which are not caught will cause program termination, by invoking function terminate, which in turn invokes abort

29CSC 330

...Catching an Exception

• Specifying only the exception type is allowed, no object is passed, the type is simply used to select the appropriate handler

catch(exception_type) { //exception handler code}

• Specifying ellipses catches all exceptions

catch(...) { //exception handler code}

30CSC 330

Unnamed Exception Handlers -only type specified

try {float answer = quotient(numerator, denominator);cout << "\n";cout << numerator << "/"

<< denominator << " = " << answer;}catch (DivideByZeroError) { //type only error handler

cout << "ERROR: DIVIDE_BY_ZERO\n";return 1; //terminate because of error

}

Enter numerator and denominator: 3 0construct: DivByZeroObjectdelete: DivByZeroObjectERROR: DIVIDE_BY_ZEROdelete: DivByZeroObjectdelete: DivByZeroObject

31CSC 330

Catching all Exceptions

try {float answer = quotient(numerator, denominator);cout << "\n";cout << numerator << "/"

<< denominator << " = " << answer;}catch (...) { //error handler

cout << "ERROR: ERROR_IN_PROGRAM\n";return 1; //terminate because of error

}

Enter numerator and denominator: 3 0construct: DivByZeroObjectdelete: DivByZeroObjectERROR: ERROR_IN_PROGRAMdelete: DivByZeroObjectOne fewer

destructorsran

32CSC 330

... Throwing ints, doubles, etc

main(){int n = 5;double x = 5.0;try {cout << n << " factorial is " << factorial(n) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}

return 0;} 5 factorial is 120

33CSC 330

... Throwing ints, doubles, etc

main(){int n = -5;double x = 5.0;try {cout << n << " factorial is " << factorial(n) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}

return 0;}

ERROR INTEGER = -5...INT MUST BE GREATER THAN ZERO

34CSC 330

... Throwing ints, doubles, etc

main(){int n = -5;double x = 5.0;try {cout << x << " factorial is " << factorial(x) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}

return 0;}

ERROR Double = 5

...ARGUMENT CANNOT BE TYPE double

35CSC 330

Throwing from Conditional Expressions

main(){int n = 5;double x = 5.0;try {n < 0 ? throw int(n) : cout << factorial(n);}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}

return 0; //terminate normally}

120

36CSC 330

...Throwing from Conditional Expressions

main(){int n = -5;double x = 5.0;try {n < 0 ? throw int(n) : cout << factorial(n);}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}

return 0; }

ERROR INTEGER = -5...INT MUST BE GREATER THAN ZERO

37CSC 330

...Throwing from Conditional Expressions

main(){int n = -5;double x = 5.0;try {n < 0 ? throw int(n) : throw double(x);}catch ... ERROR INTEGER = -5

...INT MUST BE GREATER THAN ZERO

ERROR Double = 5...ARGUMENT CANNOT BE TYPE double

main(){int n = 5;double x = 5.0;try {n < 0 ? throw int(n) : throw double(x);}catch ...

38CSC 330

...Continuing After an Exception

main(){int n = -5;double x = 5.0;try {cout << n << " factorial is " << factorial(n) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of an error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}cout << "\n...processing continues...\n";return 0; //terminate normally

}

39CSC 330

Continuing After an Exception

main(){int n = -5;double x = 5.0;try {cout << n << " factorial is " << factorial(n) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 1; //terminate because of an error

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}cout << "\n...processing continues...\n";return 0; //terminate normally

} ERROR INTEGER = -5...INT MUST BE GREATER THAN ZERO

40CSC 330

...Continuing After an Exception

main(){int n = -5;double x = 5.0;try {cout << n << " factorial is " << factorial(n) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";return 0; //return indicating normal termination

}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}cout << "\n...processing continues...\n";return 0; //terminate normally

} ERROR INTEGER = -5...INT MUST BE GREATER THAN ZERO

Same Result

41CSC 330

...Continuing After an Exception (No Return Specified)

main(){int n = -5;double x = 5.0;try {cout << n << " factorial is " << factorial(n) <<"\n";}catch (int error) { //error handler

cout << "\nERROR INTEGER = " << error << "\n";if (error < 0)

cout << "...INT MUST BE GREATER THAN ZERO\n";}catch (double error) { //error handler

cout << "\nERROR Double = " << error << "\n";cout << "\n...ARGUMENT CANNOT BE TYPE double\n";return 1; //terminate because of error

}cout << "\n...processing continues...\n";return 0; //terminate normally

}

ERROR INTEGER = -5...INT MUST BE GREATER THAN ZERO

...processing continues...

42CSC 330

Example

//mismatch type, throw integer type //catch the double type...#include <iostream.h>

void Funct(); int main() {

try { Funct(); }

catch(double) { cerr<<"caught a double

type..."<<endl; } return 0;

} void Funct()

{ //3 is not a double but intthrow 3;

}

Output:

Change the following statement throw 3; to throw 4.123;

Output:

43CSC 330

Processing Unexpected Exceptions

unexpected()

set_unexpected()

terminate()set_terminate()

abort() exit

44CSC 330

Standard Exception HierarchiesStandard Exception Hierarchies

45CSC 330

Standard ExceptionsStandard Exceptions

• The C++ exception class serves as the base class for all exceptions thrown by certain expressions and by the Standard C++ Library.

46CSC 330

47CSC 330

Recommended