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