Exceptions and stack expansion in C + +
In the C + + exception mechanism, control moves from the throw statement to the first catch statement that can handle the raised type. When a catch statement is reached, all the automatic variables within the range between the throw statement and the catch statement are destroyed in the process named "Stack unwind." In the stack expansion, execution continues, as follows:
Controls the arrival of a try statement in the normal order of execution. Executes the protected part within a try block.
If no exception is thrown during the execution of the protected part, the catch clause that follows the TRY block is not executed. Execution continues on the statement that follows the last catch clause after the associated try block.
If an exception is thrown (either directly or indirectly) in the process of executing a protected part or in any routine that is called by a protected part, an exception object is created from an object created from the throw operand. (This means that a copy constructor might be involved.) At this point, the compiler looks for a catch clause that handles the thrown type exception in a higher-privileged execution context, or finds a catch handler that can handle any type of exception. These handlers are checked according to the order in which the catch handlers are displayed after the try block. If the appropriate handler is not found, the next dynamically enclosing try block is checked. This process continues until the outermost enclosing try block is checked.
If a matching handler is still not found, or if an exception occurs during the expansion process but before the handler obtains control, the predefined run-time function terminate is invoked. Call Terminate if an exception occurs after an exception is thrown, but before the expansion begins.
If a matching catch handler is found, and it is captured by value, the parameter is initialized by copying the exception object. If it is captured by reference, the parameter is initialized to refer to the exception object. After the initial Huafing parameter, the expansion process of the stack begins. This includes the destructor of all automatic objects that are completely constructed (but not yet destructor) between the start of the try block associated with the catch handler and the thrown site of the exception. The destructor takes place in the reverse order of construction. Executes a catch handler and the program resumes execution after the last handler (that is, the first statement or construct that is not the catch handler). Control can only enter the catch handler through the exception that is thrown, not through the case label in the GOTO statement or switch statement.
Stack Unwind sample
The following example shows how to expand the stack when an exception is thrown. The thread executes the catch statement that jumps from the throw statement in C to main, and expands each function in the process. Note the order in which Dummy objects are created and destroy them when they are out of scope. Also note that other functions are not completed except for main that contains catch statements. function A will never be returned from its call to B (), and B will never return from its call to C (). If you uncomment the definition of the Dummy pointer and the corresponding DELETE statement and run the program, be aware that the pointer will never be deleted. This illustrates what happens when a function does not provide an exception guarantee. For more information, see How to: Design for exceptions. If you comment out a catch statement, you can observe what happens when the program terminates with an unhandled exception.
#include <string> #include <iostream> using namespace std;
Class myexception{};
Class Dummy {Public:dummy (string s): MyName (s) {printmsg ("Created Dummy:");} Dummy (const dummy& Other): MyName (Other.
MyName) {printmsg ("Copy created Dummy:");}
~dummy () {printmsg ("destroyed Dummy:");}
void Printmsg (string s) {cout << s << myname << Endl;}
String myname;
int level;
};
void C (Dummy d, int i) {cout << "entering Functionc" << Endl;
D.myname = "C";
throw MyException ();
cout << "Exiting Functionc" << Endl;
} void B (Dummy d, int i) {cout << "entering functionb" << Endl;
D.myname = "B";
C (d, i + 1);
cout << "Exiting Functionb" << Endl;
} void A (Dummy d, int i) {cout << "entering Functiona" << Endl;
D.myname = "A"; dummy* PD = new Dummy ("New Dummy");
Not exception safe!!!
B (d, i + 1);
Delete PD;
cout << "Exiting Functiona" << Endl;
}int main () {cout << "entering main" << Endl;
try {Dummy D ("M");
A (d,1);
catch (myexception& e) {cout << "caught an exception of type:" << typeid (E). Name () << Endl;
} cout << "exiting Main." << Endl;
char c;
CIN >> C;
}
Output:
Entering main
Created dummy:m
copy Created dummy:m entering Functiona
copy Created
Entering FUNCTIONB
Copy created dummy:b
entering Functionc
destroyed Dummy:c destroyed dummy:b Destroyed dummy:a
destroyed dummy:m
caught an exception of Type:class myexception
Main.
Exception Specification (throw)
An exception specification is a C + + language feature deprecated in c++11. These specifications were used to provide summary information about which exceptions can be thrown from a function, but they are found to be problematic in practical applications. An exception specification that proves to be of some use is the throw () specification. For example:
void MyFunction (int i) throw ();
Tells the compiler that the function does not throw any exceptions. It is equivalent to using __declspec (nothrow). This usage is optional.
(c++11) in the ISO c++11 standard, the noexcept operator is introduced, which is supported in Visual Studio 2015 and later. Use noexcept whenever possible to specify whether a function might throw an exception.
The exception specification implemented in Visual C + + differs from the ISO C + + standard. The following table summarizes the exception specification implementations for Visual C + +:
Exception Specification |
meaning |
Throw () |
function does not throw an exception. However, if an exception is thrown from the marked throw () function, the Visual C + + compiler will not invoke the unexpected handler function. If you use throw () to mark a function, the Visual C + + compiler assumes that the function does not raise C + + exceptions and generates code accordingly. Because the C + + compiler may perform code optimizations (based on a function that does not raise any assumptions about C + + exceptions), the program may not execute correctly if the function throws an exception. |
Throw (...) |
function can throw an exception. |
Throw (Type) |
Functions can throw exceptions of type types. However, in Visual C + +. NET, this is interpreted as throw (...). |
If you use exception handling in your application, you must have one or more functions that handle the exception that is thrown. All functions that are called between the function that throws the exception and the function that handles the exception must be able to throw an exception.
The triggering behavior of a function is based on the following factors:
- Do you compile functions in C or C + +.
- The/EH compiler option you are using.
- Whether to explicitly specify an exception specification.
Explicit exception specification is not allowed for C functions.
The following table summarizes the behavior that is raised for a function:
Exception_specification.cpp
//compile with:/EHs
#include <stdio.h>
void handler () {
printf _s ("in handler\n");
}
void F1 (void) throw (int) {
printf_s ("About to throw 1\n");
if (1)
throw 1;
}
void F5 (void) throw () {
try {
f1 ();
}
catch (...) {
handler ();
}
}
Invalid, doesn ' t handle the int exception thrown from F1 ()
//Void F3 (void) throw () {
//F1 ();
}
void __declspec (nothrow) f2 (void) {
try {
f1 ();
}
catch (int) {
handler ();
}
}
Only valid if compiled WITHOUT/EHC
///EHC means assume extern "C" functions don ' t throw exceptions
extern " C "void F4 (void);
void F4 (void) {
f1 ();
}
int main () {
F2 ();
try {
f4 ();
}
catch (...) {
printf_s ("Caught exception from f4\n");
}
F5 ();
}
Output:
About to throw 1 in handler about to
throw 1
caught exception from F4 about to
throw 1 in
handler