Exception Handling - New Jersey Institute of Technology

Download Report

Transcript Exception Handling - New Jersey Institute of Technology

Exception Handling
Lesson #11
Note: CIS 601 notes were originally developed by H. Zhu for NJIT DL Program. The notes were subsequently revised by M. Deek
1
Content
 Exception
and Exception Handling
 Structure of exception handling in C++
 Exception in Templates
 Group of exceptions
 Scope
2
Choices upon an error
 Terminate
immediately
 Ignore the error
 Set an error flag, check by the caller
3
What is an Exception?
 An
error generated by the program at
run-time which would normally
terminate the execution of the
program.
 Such
as, memory exhaustion, subscript
range errors, or division by zero.
4
What is Exception
Handling?
A
mechanism that allows a program to
detect and possibly recover from
errors during execution.
 The
alternative is to terminate the
program.
5
Common Exceptions
 out-of-bound
array subscript
 arithmetic overflow
 divide by zero
 out of memory reference
 invalid function parameters
 etc.
6
Benefits of Exception
Handling
improved
readability
easier to modify code
more robust code
7
Without
Exception
Handling
8
#include <iostream.h>
#include <stdlib.h>
double hmean(double a, double b);
int main(void)
{ double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
z = hmean(x,y);
cout << "Harmonic mean of " << x << "
and " << y << " is " << z << "\n";
cout << "Enter next set of numbers <q
to quit>: ";
}
cout << "Bye!\n";
return 0;
Without
Exception
Handling
}
double hmean(double a, double b)
{
if (a == -b)
{
cout << "untenable arguments to hmean()"<<endl;
abort();
}
return 2.0 * a * b / (a + b);
}//ex11-1.cpp
9
10
With Exception Handling
#include <iostream.h>
#include <stdlib.h>
double hmean(double a, double b);
int main(void)
{ double x, y, z;
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try {
z = hmean(x,y);
}
// end of try block
11
With Exception Handling
catch (const char * s) // start of exception handler
{
cout << s << "\n";
cout << "Enter a new pair of numbers: ";
continue;
}
// end of handler
cout << "Harmonic mean of " << x << " and " << y
<< " is " << z << "\n";
cout << "Enter next set of numbers <q to quit>: ";
}
cout << "Bye!\n";
return 0;
}
12
With Exception Handling
double hmean(double a, double b)
{
if (a == -b)
throw "bad hmean() arguments: a =
-b not allowed";
return 2.0 * a * b / (a + b);
}//ex11-2.cpp
13
14
Structure of Exception
Handling
try {
statement-list
}
catch(exception) {
statement-list
}
catch(exception) {
statement-list
}
15
Procedure for
exception handling
try{ func();//1.The program call in try{}
}
catch(Class anObj){…
//3.Transfer the execution to the program
}
func(){ throw exObj;
//2.The function throws an exception and transfer the
//execution to the catch block,and assign the exObj
//to anObj
}
16
Naming of an Exception
17
#include <iostream.h>
class ZeroDivide {
const char* errmsg;
public:
ZeroDivide()
: errmsg("Error: dividing by zero") { }
void print() { cout << errmsg; }
};
float divide(int n1, int n2);
void main()
{ int a, b;
cout <<"Input two integers:";
Naming
cin >> a >> b;
try { float c = divide(a,b);
cout << "a / b = " << c << '\n';
}
catch (ZeroDivide err)
{ err.print(); }
cout <<“\n”<< "end of program\n";
18
}
float divide(int n1, int n2)
{ if (n2 == 0) throw ZeroDivide();
return (float) n1 / n2;
}//ex11-3.cpp
Results:
Input two integers:34 0
Error: dividing by zero
end of program
Example
19
#include <iostream.h>
const unsigned ArraySize = 50;
int array[ArraySize];
class RangeError{};
void InsertValue(unsigned i, int value)
{ if (i>=ArraySize) throw RangeError();
array[i] = value;
}
void TestTheArray()
{ unsigned j ;
int anInt;
cout <<"Enter a subscript and a value:";
cin >> j >> anInt;
InsertValue(j, anInt);
20
Example
}
void main()
{ try
{
TestTheArray();
}
catch (const RangeError &)
{ cout <<"Range Error in main()!"<< endl;
}
}//ex11-4.cpp
21
Passing Data with
Exceptions
22
#include <iostream.h>
class array {
int* v, lower, upper;
public:
class SubscriptError {
int index;
public:
SubscriptError(int i) : index(i) { };
int get() { return index; };
};
array(int l, int u):lower(l), upper(u){
v = new int [upper-lower +1];
};
int& operator[](int);
~array(){delete [] v;}
};
23
int& array::operator[](int i)
{ if (i>=lower && i<=upper)
return *(v+i-lower);
throw SubscriptError(i);
return *v;
};
void fun(array& a)
{ try { a[100]; }
catch (array::SubscriptError s) {
cerr <<"illegal subscript:" <<s.get() << '\n';
}
}
void main()
{ array ar(20, 40);
fun (ar);
}//ex-5.cpp
24
More than
One Exception
const MAX = 500;
class array {
int* v, lower, upper;
public:
//…
class SizeError {};
array(int l, int u):lower(l), upper(u){
int size = upper-lower+1;
if (size<0 || size>MAX)
If we add another
throw SizeError();
exception SizeError, how
else { v = new int[size]; }
is it done?
};
};
25
More than One
Exception
void main()
{ int l, u;
try {
cout << "Input two bounds for the array:";
cin >> l>>u;
array ar(l, u);
fun (ar);
}
catch (array::SizeError ){
cerr <<"illegal size:" <<u - l +1 << '\n';
}
}//ex11-6.cpp
26
27
Unwinding the
Exception Stack
 Stack
unwinding:
 When
a program throw an exception, the
destructor is called for each object that
was constructed when the program
entered the try block.
28
Unwinding the
Exception Stack
 When
an exception is thrown during
the construction of a composite object,
destructors will be invoked only for
those data members that have already
been constructed.
29
Unwinding
30
#include <iostream.h>
#include <string.h>
class Test{};
class VString{
public:
VString(){ };
VString(char *s){ };
~VString(){cout <<"VString Des!"<<endl;};
};
class Transcript{
public:
Transcript(){
throw Test();
};
~Transcript(){cout <<"Transcript Des!"<<endl;};
};
Unwinding
class Student{
VString lastName;
Transcript records;
public:
Student(){};
~Student(){cout <<"Student Des!"<<endl;};
};
void main()
{ try{
VString collegeName("NJIT");
Student S;
}
catch (...) {cout << "exception!"<<endl;
}
}//ex11-7.cpp
31
32
Multiple Handlers
 Most
programs performing exception
handling have to handle more than
one type of exception. A single try
block can be followed by multiple
handlers(catch), each configured to
match a different exception type.
33
Example
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
class RangeError { }; //Exception
class InputFileError { }; //Exception
class LongArray {
public:
LongArray( unsigned sz = 0 );
~LongArray();
long Get( unsigned i ) const;
private:
long * data; // array of long integers
unsigned size; // allocation size
};//cis601source/chap8/except/except2.cpp
34
Example
LongArray::LongArray( unsigned sz )
{ size = sz;
data = new long[size];
}
LongArray::~LongArray()
{ delete [] data;}
long LongArray::Get( unsigned i ) const
{ if( i >= size )
throw RangeError();
return data[i];
}
35
Example
unsigned ArraySize = 50;
void ReadFile( ifstream & infile, LongArray & L )
{ infile.open( "INDATA.TXT" );
if( !infile )
throw InputFileError();
}
void GetArrayElement( const LongArray & L )
{ unsigned i;
cout << "Enter subscript: ";
cin >> i;
long n = L.Get( i );
}
36
Example
int main()
{ try {
ifstream infile;
LongArray L( ArraySize );
ReadFile( infile, L );
GetArrayElement( L );
cout << "Program completed normally.\n";
}
catch( const RangeError & R ) {
cout << "Subscript out of range\n"; }
catch( const InputFileError & F ) {
cout << "Unable to open input file\n"; }
catch( ... ) { cout << "Unknown exception thrown\n"; }
return 0;
37 }//except2.cpp
Results
Enter subscript: 23
Program completed normally.
Enter subscript: 56
Subscript out of range
38
Ex: RangeError Class
39
#include <iostream.h>
#include <stdlib.h>
#include <fstream.h>
#include "fstring.h"
#include "range.h"
class LongArray {
public:
LongArray( unsigned sz = 0 ){size = sz; data = new long [sz];};
~LongArray() {delete [] data;};
unsigned GetSize() const;
long Get( unsigned i ) const;
void Put( unsigned i, long item );
private:
long * data; // array of long integers
unsigned size; // allocation size
}; //cis601source/chap8/except/except3.cpp
Range.h
#include <iostream.h>
#include <string.h>
const unsigned FileNameSize = 50;
// Make this >= longest filename on target system.
class RangeError {
public:
RangeError( const char * fname,
unsigned line,
unsigned subscr )
{
strncpy(fileName, fname, FileNameSize);
lineNumber = line;
value = subscr;
}
40
Range.h
friend ostream & operator <<( ostream & os,
const RangeError & R )
{ os << "\nRangeError exception thrown: "
<< R.fileName
<< ", line " << R.lineNumber
<< " value = " << R.value
<< endl;
return os;
}
private:
char fileName[FileNameSize+1];
unsigned lineNumber;
unsigned value;
};
41
The name of the current source file. __FILE__ expands
to a string surrounded by double quotation marks.
RangeError
inline unsigned LongArray::GetSize() const
{ return size;}
inline void LongArray::Put( unsigned i, long item )
{ if( i >= size )
throw RangeError( __FILE__ ,__LINE__, i );
data[i] = item;
}
inline long LongArray::Get( unsigned i ) const
{ if( i >= size )
throw RangeError( __FILE__ ,__LINE__, i );
return data[i];
}
The line number in the current source file. The
42
line number is a decimal constant.
43
unsigned GetArraySize()
{ unsigned n;
cout << "Number of array elements? ";
cin >> n;
return n;
}
void FillArray( LongArray & L )
{ int i;
try { for( i = 0; i < L.GetSize(); i++ )
L.Put( i, rand() );
}
catch( const RangeError & R ) {
cout << R;
throw R;
}
}
RangeError
RangeError
44
void GetArrayElement( const LongArray & L )
{ int ok = 0;
while( !ok )
{ unsigned i;
cout << "Enter an array subscript (0-"<< ( L.GetSize()-1 ) << "): ";
cin >> i;
long n;
try { n = L.Get( i );
ok = 1;
cout << "Element contains " << n << endl; }
catch( const RangeError & R ) {
cout << R;
cout << "Caught at: " << __FILE__<< ", line " << __LINE__ << endl;
throw; }
}
}
RangeError
int main()
{
try {
LongArray L( GetArraySize() );
FillArray( L );
GetArrayElement( L );
}
catch( ... ) {
cout << "Exception caught in main().\n";
return 1;
}
return 0;
}//except3.cpp
45
46
Exception with no
Catch
If
no catch matches the
exception generated by the try
block, the search continues with
the next enclosing try block.
If no catch is found, then error!
47
void fun1(array& a)
{ ...
try {
fun2(a); ...
}
catch (array::SubscriptError) { ...
}
...
}
48
void fun2(array& a)
{
...
try {
... // use array a
}
catch (array::SizeError) { ...
}
...
}
49
Exception within an
Exception
If
the same exception type is
raised while handling the
exception of a try block, then the
new exception is handled by the
outer try block.
50
No Infinite Loop
#include <iostream.h>
class Over{};
void fun(){cout << "fun"<<endl;
throw Over();
}
void main()
{
try {
fun();
}
catch (Over) {
cout <<"Over1"<<endl;
throw Over();
}
}//ex11-8.cpp
51
52
Nesting Exception
Handlers
 Exception
handlers may be nested.
 Nesting is rarely needed or useful.
 Nesting can make the code difficult to
read.
53
#include <iostream.h>
class Over{};
void fun(){cout << "fun"<<endl;
throw Over(); }
void main()
{ try { fun(); }
catch (Over) {
cout <<"Over1"<<endl;
try { fun(); }
catch (Over)
{cout <<"Over2"<<endl;
}
}//ex11-9.cpp
54
}
55
Exceptions in
Templates
 Each
class generated can have its
own exception class, or
 we can have one exception that is
common to all the classes generated
from the template.
56
template<class TP>
class array {
TP* v;
int lower, int upper;
public:
class Exception { };
...
};
57
void fun(array<int>& intArr, array<float>& fltArr)
{
try {
...
}
catch (array<int>::Exception) { ... }
catch (array<float>::Exception) { ... }
}
58
A common Exception
for a Class Template
class Exception { } ;
template<class TP> class array {
...
};
59
void fun(array<int>& intArr, array<float>& fltArr)
{
try {
...
}
catch (Exception) {
...
}
}
60
Grouping of
Exceptions
 When
a set of exceptions are
considered to be logically related, it is
often best to organize them into a
family of exceptions.
61
enum Exception { Ex1, Ex2, Ex3, ... };
try { ...
}
catch (Exception e) {
switch (e) {
case Ex1: ....
case Ex2: ....
...
}
...
}
62
Using Inheritance
class Exception { };
class Ex1 : public Exception { };
class Ex2 : public Exception { };
class Ex3 : public Exception { };
...
63
try {
...
}
catch (Ex1) {
...
}
catch (Exception) {
...
}//ex11-11.cpp
64
Derived Exceptions
#include <iostream.h>
const MAXINT =200;
const MININT =0;
class Matherr {
public:
virtual void debug_print(){};
};
class int_overflow: public Matherr {
public:
char* op;
int opr1, opr2;
int_overflow( char* p, int a, int b)
{ op = p; opr1 = a; opr2 = b; }
virtual void debug_print()
{ cerr << op << '(' << opr1 <<
',' << opr2 <<')' <<endl;
65 };
}
int add(int x, int y)
{
if( x > 0 && y > 0 && x > MAXINT - y
|| x < 0 && y < 0 && x < MININT - y)
throw int_overflow("+", x, y);
return x + y;
}
void f( )
{
try {
add(1, 2);
add(MAXINT, -2);
add(MAXINT, 2);
}
catch (Matherr& m) {
m.debug_print( );
}
66 }
Result:
void main( )
+(200,2)
{
try {
f();
}
catch ( Matherr) {
cout <<"catch another Matherr"<<endl;
}
}//ex11-10.cpp
67
Re-throwing an
Exception
 In
some cases when an exception
handler is unable to deal with the
exception it can re-throw the exception
to allow another handler to deal with it.
 The
68
original exception is re-thrown.
void fun()
{
try { ... }
catch (Exception) {
if ( ... )
{ ...
}
else
throw;
}
}
69
A Catch for All
Exceptions
void fun()
{
try { g();
}
catch (...) {
// do some handling
throw;
}
}
70
The Order of Handlers
 A handler
 it
matches if:
directly refers to the exception thrown.
 it is of a base class of that exception.
71
Exception Interface
Specification
int fun( ) throw (Ex1, Ex2, Ex3)
{
...
}
 Specifies
that fun may throw
exceptions Ex1, Ex2, and Ex3 and any
other exceptions derived from them.
72
Interface Specification
 A function
that can throw any
exception
void fun();
 A function
that do not throw any
exception:
void fun() throw;
73
Unexpected
Exceptions
 If
a function throws an exception not
listed or covered by its interface, the
function unexpected is called, which
results with a call to terminate().
 The meaning of unexpected can be
redefined using the function
set_unexpected().
74
void fun() throw(Ex1, Ex2) { ... }
is equivalent to:
void fun() {
try {
...
}
catch (Ex1) { throw; }
catch (Ex2) { throw; }
catch (...) { unexpected(); }
}
75
What Should an
Exception Handler Do?
 fix
the problem and try again
 Re-throw the exception
 Re-throw another exception
 return the needed result
76
Scoping Rules
 variables
declared within a try block
are not accessible outside the block.
 variables declared within one catch
block may not be accessed from other
catch blocks.
 variables declared at the beginning of a
function may be accessed throughout
the try and catch blocks.
77
Resource Acquisition
 When
a function uses a resource, it is
important for the resource to be
properly released at the end, even
when errors are encountered during
the use of the resource.
78
Example
void fun(char* s)
{
FILE* fp = fopen(s, “r”);
...
fclose(f);
}
79
One Approach
{
File* fp = fopen(s, “r”);
try { ... }
catch (...) {
fclose (fp);
throw;
}
fclose(fp);
}
80
A Better Approach
class File {
FILE* fp;
public:
File(char* name, char* access)
{ fp = open(name, access); }
~File()
{ fclose(fp); }
...
};
81
Exception Handling vs.
Control Structures
 Exception
handling is a less structured
mechanism than language control
structures.
 Exception handling is usually less
efficient than control mechanisms.
 When used for dealing with situations
other than errors, it could lead to less
understandable code.
82
Readings
 Reading:
 8.3,8.4
83