410 likes | 545 Views
Exceptions. NKU CSC 601 Fall 2002 K. Kirby. This week’s readings Stroustrup Chapter 10. Classes Chapter 12. Derived classes Chapter 14. Exception handing. TODAY. NKU CSC 601 Fall 2002 K. Kirby. What’s an error?. What can you do with errors? Let an assertion fail?
E N D
Exceptions NKU CSC 601 Fall 2002 K. Kirby
This week’s readings Stroustrup Chapter 10. Classes Chapter 12. Derivedclasses Chapter 14. Exception handing TODAY NKU CSC 601 Fall 2002 K. Kirby
What’s an error? • What can you do with errors? • Let an assertion fail? • Use assertions only as comments with runtime force. For cases that should never fail. A way to comment on pre-/post- conditions and invariants. • Write error message and prompt? and quit?Write it where? (Is there a console?) Can we just quit without knowing the context?! • Return error code?Well, COM does it. But it’s ridiculous to force programmers to check each call. • Leave object in error state? • Not bad, but too ad hoc. • Throw an exceptionYes. We can respond when and where we care, but without discarding information. NKU CSC 601 Fall 2002 K. Kirby
Exception Issues Throwing and catching Specifications Standard exceptions Resource control NKU CSC 601 Fall 2002 K. Kirby
Throwing is easy. void f() { cout << “Enter a positive number” ; cin >> n ; if ( n < 0 ) ; throw “a tantrum” ; // .. etc. } No “Throwable” class like Java. Throw anything! NKU CSC 601 Fall 2002 K. Kirby
Catching is easy too. void something() { try { // ... etc. f() ; // ... etc . } catch ( const char* s ) { cerr << “Caught:” << s << endl ; } } NKU CSC 601 Fall 2002 K. Kirby
What To Throw Best to throw objects of type exception (in <exception>). Even better to throw a standard one (in <stdexcept>). #include <stdexcept> void f() { cout << “Enter a positive number” ; cin >> n ; if ( n < 0 ) ; throw runtime_error( “negative n” ) ; // .. etc. } anonymous construction! NOT new runtime_error( ... ) ; We are not throwing a pointer! NKU CSC 601 Fall 2002 K. Kirby
Catching a standard exception... by reference? void something() { try { // ... etc. f() ; // ... etc . } catch ( runtime_error& e ) { cerr << “Caught:” << e.what() << endl ; } } what is a reference, really? NKU CSC 601 Fall 2002 K. Kirby
Specifications Say what you are going to throw. This includes what is thrown (and uncaught) by functions you call yourself. List everything that could be thrown: void f() throw ( runtime_error, logic_error ) ; To say f won’t throw anything, write this: void f() throw() ; This means “might throw anything”: void something() ; Not “throws” (contra Java) NKU CSC 601 Fall 2002 K. Kirby
The Best Thing About Exception Handling When an exception is thrown out of a function, all destructors of objects named by local variables are called. NKU CSC 601 Fall 2002 K. Kirby
When an exception is thrown out of a function, all destructors of objects named by local variables are called. To benefit from this nice feature... Do this: DON’T DO THIS! void f( int n ) { Thing th( 7 ) ; vector<int> v( n ) ; // stuff... } void f( int n ) { Thing* pt= new Thing(7) ; int* ar= new int[n] ; // stuff... delete pt ; delete [] ar ; } Avoid dumb pointers if you can! NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } Exceptions: A Tour NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(2) c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(2) c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(2) c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(0) c recur(2) c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } recur(0) c recur(2) c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(0) c recur(2) c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(2) dtor called c recur(4) c play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(4) c dtor called play(4) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! play(4) starter dtor called main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(3) c play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(1) c recur(3) c play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(-1) c recur(1) c recur(3) c play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(-1) c recur(1) c recur(3) c play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(1) dtor called c recur(3) c play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! recur(3) c dtor called play(3) starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! play(3) starter dtor called main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! CAUGHT: Negative argument starter main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } …bottom! CAUGHT: Negative argument main The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
void recur( int n ) throw ( invalid_argument ) { SomeClass c ; if ( n < 0 ) throw ( invalid_argument( "Negative argument" ) ); else if ( n == 0 ) cout << "...bottom!" << endl ; else recur( n-2 ) ; } void play( int n ) throw ( logic_error ) { recur( n ) ; } void starter() throw () { try { play( 4 ) ; // should be okay play( 3 ) ; // asking for trouble } catch ( logic_error& e ) { cout << "CAUGHT: " << e.what() << endl ; } } main() { starter() ; } The Heap The Stack NKU CSC 601 Fall 2002 K. Kirby
Memory Overflow For the New Millennium 20th century: int* p = new int [ BIGNUM ] ; if ( p == NULL ) // sorry, could not allocate else // use p[] 21st century: will throw a bad_alloc exception if allocation fails (catch it if you like) #include <memory> int* p = new int [ BIGNUM ] ; // use p[] NKU CSC 601 Fall 2002 K. Kirby