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 that have completed intitialization 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, the program terminates. The program of Fig. 17.4 demonstrates stack unwinding.
1 // Fig. 17.4: fig17_04.cpp
2 // Demonstrating stack unwinding.
3 #include <iostream>
4 #include <stdexcept>
5 using namespace std;
6
7 // function3 throws runtime error
8 void function3()
9 {
10 cout << "In function 3" << endl;
11
12 // no try block, stack unwinding occurs, return control to function2
13 throw runtime_error( "runtime_error in function3" ); // no print
14 } // end function3
15
16 // function2 invokes function3
17 void function2()
18 {
19 cout << "function3 is called inside function2" << endl;
20 function3(); // stack unwinding occurs, return control to function1
21 } // end function2
22
23 // function1 invokes function2
24 void function1()
25 {
26 cout << "function2 is called inside function1" << endl;
27 function2(); // stack unwinding occurs, return control to main
28 } // end function1
29
30 // demonstrate stack unwinding
31 int main()
32 {
33 // invoke function1
34 try
35 {
36 cout << "function1 is called inside main" << endl;
37 function1(); // call function1 which throws runtime_error
38 } // end try
39 catch ( runtime_error &error ) // handle runtime error
40 {
41 cout << "Exception occurred: " << error.what() << endl;
42 cout << "Exception handled in main" << endl;
43 } // end catch
44 } // end main
In main
, the try
block (lines 34–38) calls function1
(lines 24–28). Next, function1
calls function2
(lines 17–21), which in turn calls function3
(lines 8–14). Line 13 of function3
throws a runtime_error
object. However, because no try
block encloses the throw
statement in line 13, stack unwinding occurs—function3
terminates at line 13, then returns control to the statement in function2
that invoked function3
(i.e., line 20). Because no try
block encloses line 20, stack unwinding occurs again—function2
terminates at line 20 and returns control to the statement in function1
that invoked function2
(i.e., line 27). Because no try
block encloses line 27, stack unwinding occurs one more time—function1
terminates at line 27 and returns control to the statement in main
that invoked function1
(i.e., line 37). The try
block of lines 34–38 encloses this statement, so the first matching catch
handler located after this try
block (line 39–43) catches and processes the exception. Line 41 uses function what
to display the exception message.