840 likes | 1.2k Views
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. Content. Exception and Exception Handling Structure of exception handling in C++ Exception in Templates Group of exceptions Scope.
E N D
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
Content • Exception and Exception Handling • Structure of exception handling in C++ • Exception in Templates • Group of exceptions • Scope
Choices upon an error • Terminate immediately • Ignore the error • Set an error flag, check by the caller
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.
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.
Common Exceptions • out-of-bound array subscript • arithmetic overflow • divide by zero • out of memory reference • invalid function parameters • etc.
Benefits of Exception Handling • improved readability • easier to modify code • more robust code
Without 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) { z = hmean(x,y); cout << "Harmonic mean of " << x << " and " << y << " is " << z << "\n"; cout << "Enter next set of numbers <q to quit>: "; }
Without Exception Handling cout << "Bye!\n"; return 0; } 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
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
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; }
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
try { statement-list } catch(exception) { statement-list } catch(exception) { statement-list } Structure of Exception Handling
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 }
Naming of an Exception #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"; } 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 #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:";
Example cin >> j >> anInt; InsertValue(j, anInt); } void main() { try { TestTheArray(); } catch (const RangeError &) { cout <<"Range Error in main()!"<< endl; } }//ex11-4.cpp
Passing Data with Exceptions #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;} };
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
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) throw SizeError(); else { v = new int[size]; } }; }; If we add another exception SizeError, how is it done?
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
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.
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.
Unwinding #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
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.
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
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]; }
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 ); }
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; }//except2.cpp
Results Enter subscript: 23 Program completed normally. Enter subscript: 56 Subscript out of range
Ex: RangeError Class #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; }
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; };
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 line number is a decimal constant.
RangeError 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 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
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!
void fun1(array& a) { ... try { fun2(a); ... } catch (array::SubscriptError) { ... } ... }
void fun2(array& a) { ... try { ... // use array a } catch (array::SizeError) { ... } ... }
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.