Stack Unwinding
When an exception is thrown but not caught in a particular scope, the function call stack is unwound, and an attempt is made to catch the exception in the next outer TRy... catch block. Unwinding the function call stack means that the function in which the exception was not caught terminates, all local variables in that function are destroyed and control returns to the statement that originally invoked that function. If a TRy block encloses that statement, an attempt is made to catch the exception. If a try block does not enclose that statement, stack unwinding occurs again. If no catch handler ever catches this exception, function terminate is called to terminate the program. The program of Fig. 16.4 demonstrates stack unwinding.
Figure 16.4. Stack unwinding.
(This item is displayed on pages 823 - 824 in the print version)
1 // Fig. 16.4: Fig16_04.cpp 2 // Demonstrating stack unwinding. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::runtime_error; 9 10 // function3 throws run-time error 11 void function3() throw ( runtime_error ) 12 { 13 cout << "In function 3" << endl; 14 15 // no try block, stack unwinding occur, return control to function2 16 throw runtime_error( "runtime_error in function3" ); 17 } // end function3 18 19 // function2 invokes function3 20 void function2() throw ( runtime_error ) 21 { 22 cout << "function3 is called inside function2" << endl; 23 function3(); // stack unwinding occur, return control to function1 24 } // end function2 25 26 // function1 invokes function2 27 void function1() throw ( runtime_error ) 28 { 29 cout << "function2 is called inside function1" << endl; 30 function2(); // stack unwinding occur, return control to main 31 } // end function1 32 33 // demonstrate stack unwinding 34 int main() 35 { 36 // invoke function1 37 try 38 { 39 cout << "function1 is called inside main" << endl; 40 function1(); // call function1 which throws runtime_error 41 } // end try 42 catch ( runtime_error &error ) // handle run-time error 43 { 44 cout << "Exception occurred: " << error.what() << endl; 45 cout << "Exception handled in main" << endl; 46 } // end catch 47 48 return 0; 49 } // end main
|
In main, the TRy block (lines 3741) calls function1 (lines 2731). Next, function1 calls function2 (lines 2024), which in turn calls function3 (lines 1117). Line 16 of function3 tHRows a runtime_error object. However, because no try block encloses the tHRow statement in line 16, stack unwinding occursfunction3 terminates at line 16, then returns control to the statement in function2 that invoked function3 (i.e., line 23). Because no try block encloses line 23, stack unwinding occurs againfunction2 terminates at line 23 and returns control to the statement in function1 that invoked function2 (i.e., line 30). Because no try block encloses line 30, stack unwinding occurs one more timefunction1 terminates at line 30 and returns control to the statement in main that invoked function1 (i.e., line 40). The try block of lines 3741 encloses this statement, so the first matching catch handler located after this try block (line 4246) catches and processes the exception. Line 44 uses function what to display the exception message. Recall that function what is a virtual function of class exception that can be overridden by a derived class to return an appropriate error message.