C++ 16 Exception Handling
C++ 16 Exception Handling
Article • 08/03/2021
An exception is an error condition, possibly outside the program's control, that prevents
the program from continuing along its regular execution path. Certain operations,
including object creation, file input/output, and function calls made from other modules,
are all potential sources of exceptions, even when your program is running correctly.
Robust code anticipates and handles exceptions. To detect logic errors, use assertions
rather than exceptions (see Using Assertions).
Kinds of exceptions
The Microsoft C++ compiler (MSVC) supports three kinds of exception handling:
For most C++ programs, you should use C++ exception handling. It's type-safe,
and ensures that object destructors are invoked during stack unwinding.
MFC exceptions
Since version 3.0, MFC has used C++ exceptions. It still supports its older exception
handling macros, which are similar to C++ exceptions in form. For advice about
mixing MFC macros and C++ exceptions, see Exceptions: Using MFC Macros and
C++ Exceptions.
Use an /EH compiler option to specify the exception handling model to use in a C++
project. Standard C++ exception handling (/EHsc) is the default in new C++ projects in
Visual Studio.
We don't recommend you mix the exception handling mechanisms. For example, don't
use C++ exceptions with structured exception handling. Using C++ exception handling
exclusively makes your code more portable, and it allows you to handle exceptions of
any type. For more information about the drawbacks of structured exception handling,
see Structured Exception Handling.
In this section
Modern C++ best practices for exceptions and error handling
Exception Specifications
noexcept
See also
C++ Language Reference
x64 exception handling
Exception Handling (C++/CLI and C++/CX)
Modern C++ best practices for
exceptions and error handling
Article • 03/22/2024
In modern C++, in most scenarios, the preferred way to report and handle both logic
errors and runtime errors is to use exceptions. It's especially true when the stack might
contain several function calls between the function that detects the error, and the
function that has the context to handle the error. Exceptions provide a formal, well-
defined way for code that detects errors to pass the information up the call stack.
these cases, it's up to the caller to recognize the code and respond to it appropriately. If
the caller doesn't explicitly handle the error code, the program might crash without
warning. Or, it might continue to execute using bad data and produce incorrect results.
An exception forces calling code to recognize an error condition and handle it.
Unhandled exceptions stop program execution.
An exception jumps to the point in the call stack that can handle the error.
Intermediate functions can let the exception propagate. They don't have to
coordinate with other layers.
The exception stack-unwinding mechanism destroys all objects in scope after an
exception is thrown, according to well-defined rules.
An exception enables a clean separation between the code that detects the error
and the code that handles the error.
The following simplified example shows the necessary syntax for throwing and catching
exceptions in C++:
C++
#include <stdexcept>
#include <limits>
#include <iostream>
void MyFunc(int c)
{
if (c > numeric_limits< char> ::max())
{
throw invalid_argument("MyFunc argument too large.");
}
//...
}
int main()
{
try
{
MyFunc(256); //cause an exception to throw
}
catch (invalid_argument& e)
{
cerr << e.what() << endl;
return -1;
}
//...
return 0;
}
Exceptions in C++ resemble ones in languages such as C# and Java. In the try block, if
an exception is thrown it is caught by the first associated catch block whose type
matches that of the exception. In other words, execution jumps from the throw
statement to the catch statement. If no usable catch block is found, std::terminate is
invoked and the program exits. In C++, any type may be thrown; however, we
recommend that you throw a type that derives directly or indirectly from
std::exception . In the previous example, the exception type, invalid_argument, is
defined in the standard library in the <stdexcept> header file. C++ doesn't provide or
require a finally block to make sure all resources are released if an exception is
thrown. The resource acquisition is initialization (RAII) idiom, which uses smart pointers,
provides the required functionality for resource cleanup. For more information, see How
to: Design for exception safety. For information about the C++ stack-unwinding
mechanism, see Exceptions and stack unwinding.
Basic guidelines
Robust error handling is challenging in any programming language. Although
exceptions provide several features that support good error handling, they can't do all
the work for you. To realize the benefits of the exception mechanism, keep exceptions in
mind as you design your code.
Use asserts to check for conditions that should always be true or always be false.
Use exceptions to check for errors that might occur, for example, errors in input
validation on parameters of public functions. For more information, see the
Exceptions versus assertions section.
Use exceptions when the code that handles the error is separated from the code
that detects the error by one or more intervening function calls. Consider whether
to use error codes instead in performance-critical loops, when code that handles
the error is tightly coupled to the code that detects it.
For every function that might throw or propagate an exception, provide one of the
three exception guarantees: the strong guarantee, the basic guarantee, or the
nothrow ( noexcept ) guarantee. For more information, see How to: Design for
exception safety.
Throw exceptions by value, catch them by reference. Don't catch what you can't
handle.
Don't use exception specifications, which are deprecated in C++11. For more
information, see the Exception specifications and noexcept section.
Use standard library exception types when they apply. Derive custom exception
types from the exception Class hierarchy.
Don't allow exceptions to escape from destructors or memory-deallocation
functions.
For more information about SEH, see Structured Exception Handling (C/C++).
See also
How to: Interface between exceptional and non-exceptional code
C++ language reference
C++ Standard Library
Feedback
Was this page helpful? Yes No
One of the advantages of the exception mechanism is that execution, together with data
about the exception, jumps directly from the statement that throws the exception to the
first catch statement that handles it. The handler may be any number of levels up in the
call stack. Functions that are called between the try statement and the throw statement
are not required to know anything about the exception that is thrown. However, they
have to be designed so that they can go out of scope "unexpectedly" at any point where
an exception might propagate up from below, and do so without leaving behind
partially created objects, leaked memory, or data structures that are in unusable states.
Basic techniques
A robust exception-handling policy requires careful thought and should be part of the
design process. In general, most exceptions are detected and thrown at the lower layers
of a software module, but typically these layers do not have enough context to handle
the error or expose a message to end users. In the middle layers, functions can catch
and rethrow an exception when they have to inspect the exception object, or they have
additional useful information to provide for the upper layer that ultimately catches the
exception. A function should catch and "swallow" an exception only if it is able to
completely recover from it. In many cases, the correct behavior in the middle layers is to
let an exception propagate up the call stack. Even at the highest layer, it might be
appropriate to let an unhandled exception terminate a program if the exception leaves
the program in a state in which its correctness cannot be guaranteed.
C++
// old-style new/delete version
class NDResourceClass {
private:
int* m_p;
float* m_q;
public:
NDResourceClass() : m_p(0), m_q(0) {
m_p = new int;
m_q = new float;
}
~NDResourceClass() {
delete m_p;
delete m_q;
}
// Potential leak! When a constructor emits an exception,
// the destructor will not be invoked.
};
// shared_ptr version
#include <memory>
class SPResourceClass {
private:
shared_ptr<int> m_p;
shared_ptr<float> m_q;
public:
SPResourceClass() : m_p(new int), m_q(new float) { }
// Implicitly defined dtor is OK for these members,
// shared_ptr will clean up and avoid leaks regardless.
};
class Shape {
// ...
};
class SPShapeResourceClass {
private:
shared_ptr<Shape> m_p;
shared_ptr<Shape> m_q;
public:
SPShapeResourceClass() : m_p(new Circle), m_q(new Triangle) { }
};
No-fail guarantee
The no-fail (or, "no-throw") guarantee is the strongest guarantee that a function can
provide. It states that the function will not throw an exception or allow one to
propagate. However, you cannot reliably provide such a guarantee unless (a) you know
that all the functions that this function calls are also no-fail, or (b) you know that any
exceptions that are thrown are caught before they reach this function, or (c) you know
how to catch and correctly handle all exceptions that might reach this function.
Both the strong guarantee and the basic guarantee rely on the assumption that the
destructors are no-fail. All containers and types in the Standard Library guarantee that
their destructors do not throw. There is also a converse requirement: The Standard
Library requires that user-defined types that are given to it—for example, as template
arguments—must have non-throwing destructors.
Strong guarantee
The strong guarantee states that if a function goes out of scope because of an
exception, it will not leak memory and program state will not be modified. A function
that provides a strong guarantee is essentially a transaction that has commit or rollback
semantics: either it completely succeeds or it has no effect.
Basic guarantee
The basic guarantee is the weakest of the three. However, it might be the best choice
when a strong guarantee is too expensive in memory consumption or in performance.
The basic guarantee states that if an exception occurs, no memory is leaked and the
object is still in a usable state even though the data might have been modified.
Exception-safe classes
A class can help ensure its own exception safety, even when it is consumed by unsafe
functions, by preventing itself from being partially constructed or partially destroyed. If a
class constructor exits before completion, then the object is never created and its
destructor will never be called. Although automatic variables that are initialized prior to
the exception will have their destructors invoked, dynamically allocated memory or
resources that are not managed by a smart pointer or similar automatic variable will be
leaked.
The built-in types are all no-fail, and the Standard Library types support the basic
guarantee at a minimum. Follow these guidelines for any user-defined type that must be
exception-safe:
Use smart pointers or other RAII-type wrappers to manage all resources. Avoid
resource management functionality in your class destructor, because the
destructor will not be invoked if the constructor throws an exception. However, if
the class is a dedicated resource manager that controls just one resource, then it's
acceptable to use the destructor to manage resources.
Consider whether to store all class state in a data member that is wrapped in a
smart pointer, especially if a class has a concept of "initialization that is permitted
to fail." Although C++ allows for uninitialized data members, it does not support
uninitialized or partially initialized class instances. A constructor must either
succeed or fail; no object is created if the constructor does not run to completion.
Do not allow any exceptions to escape from a destructor. A basic axiom of C++ is
that destructors should never allow an exception to propagate up the call stack. If
a destructor must perform a potentially exception-throwing operation, it must do
so in a try catch block and swallow the exception. The standard library provides
this guarantee on all destructors it defines.
See also
Modern C++ best practices for exceptions and error handling
How to: Interface Between Exceptional and Non-Exceptional Code
How to: Interface between exceptional
and non-exceptional code
Article • 03/02/2022
This article describes how to implement consistent exception-handling in C++ code, and
how to translate exceptions to and from error codes at exception boundaries.
Sometimes C++ code has to interface with code that doesn't use exceptions (non-
exceptional code). Such an interface is known as an exception boundary. For example,
you may want to call the Win32 function CreateFile in your C++ program. CreateFile
doesn't throw exceptions. Instead, it sets error codes that can be retrieved by the
GetLastError function. If your C++ program is non-trivial, then you probably prefer to
have a consistent exception-based error-handling policy. And, you probably don't want
to abandon exceptions just because you interface with non-exceptional code. You also
don't want to mix exception-based and non-exception-based error policies in your C++
code.
Example
The following example shows C++ functions that use the Win32 CreateFile and
ReadFile functions internally to open and read two files. The File class is a resource
acquisition is initialization (RAII) wrapper for the file handles. Its constructor detects a
"file not found" condition and throws an exception to propagate the error up the call
stack of the C++ executable (in this example, the main() function). If an exception is
thrown after a File object is fully constructed, the destructor automatically calls
CloseHandle to release the file handle. (If you prefer, you can use the Active Template
Library (ATL) CHandle class for this same purpose, or a unique_ptr together with a
custom deletion function.) The functions that call Win32 and CRT APIs detect errors and
then throw C++ exceptions using the locally defined ThrowLastErrorIf function, which
in turn uses the Win32Exception class, derived from the runtime_error class. All
functions in this example provide a strong exception guarantee: If an exception is
thrown at any point in these functions, no resources are leaked and no program state is
modified.
C++
class File
{
private:
HANDLE m_handle;
~File() { CloseHandle(m_handle); }
vector<char> readbuffer(filesize);
cout << filename << " file size: " << filesize << ", bytesRead: "
<< bytesRead << endl;
return readbuffer;
}
try
{
if(argc > 2) {
filename1 = argv[1];
filename2 = argv[2];
}
cout << "Using file names " << filename1 << " and " << filename2 <<
endl;
if (IsFileDiff(filename1, filename2)) {
cout << "+++ Files are different." << endl;
} else {
cout<< "=== Files match." << endl;
}
}
catch(const Win32Exception& e)
{
ios state(nullptr);
state.copyfmt(cout);
cout << e.what() << endl;
cout << "Error code: 0x" << hex << uppercase << setw(8) <<
setfill('0')
<< e.GetErrorCode() << endl;
cout.copyfmt(state); // restore previous formatting
}
}
We recommend your extern "C" C++ function specifically catch every exception that it
knows how to handle and, if appropriate, convert the exception to an error code that
the caller understands. If not all potential exceptions are known, the C++ function
should have a catch(...) block as the last handler. In such a case, it's best to report a
fatal error to the caller, because your program might be in an unknown and
unrecoverable state.
The following example shows a function that assumes that any exception that might be
thrown is either a Win32Exception or an exception type derived from std::exception .
The function catches any exception of these types and propagates the error information
as a Win32 error code to the caller.
C++
catch(std::exception& e)
{
SetLastError(MY_APPLICATION_GENERAL_ERROR);
}
return FALSE;
}
When you convert from exceptions to error codes, there's a potential issue: Error codes
often don't contain the richness of information that an exception can store. To address
this issue, you can provide a catch block for each specific exception type that might be
thrown, and perform logging to record the details of the exception before it's converted
to an error code. This approach can create repetitive code if multiple functions all use
the same set of catch blocks. A good way to avoid code repetition is by refactoring
those blocks into one private utility function that implements the try and catch blocks
and accepts a function object that is invoked in the try block. In each public function,
pass the code to the utility function as a lambda expression.
C++
template<typename Func>
bool Win32ExceptionBoundary(Func&& f)
{
try
{
return f();
}
catch(Win32Exception& e)
{
SetLastError(e.GetErrorCode());
}
catch(const std::exception& e)
{
SetLastError(MY_APPLICATION_GENERAL_ERROR);
}
return false;
}
The following example shows how to write the lambda expression that defines the
functor. A lambda expression is often easier to read inline than code that calls a named
function object.
C++
You can build the entire code path across the non-exception-aware code using
/EHs ,
There aren't any locally allocated resources that can leak when the stack is
unwound,
The code doesn't have any __except structured exception handlers that catch all
exceptions.
Because throwing exceptions across non-exceptional code is error-prone and may cause
difficult debugging challenges, we don't recommend it.
See also
Modern C++ best practices for exceptions and error handling
How to: Design for exception safety
try, throw, and catch Statements (C++)
Article • 02/14/2023
To implement exception handling in C++, you use try , throw , and catch expressions.
First, use a try block to enclose one or more statements that might throw an exception.
To handle exceptions that may be thrown, implement one or more catch blocks
immediately following a try block. Each catch block specifies the type of exception it
can handle.
This example shows a try block and its handlers. Assume that GetNetworkResource()
acquires data over a network connection and that the two exception types are user-
defined classes that derive from std::exception . Notice that the exceptions are caught
by const reference in the catch statement. We recommend that you throw exceptions
by value and catch them by const reference.
Example
C++
MyData md;
try {
// Code that could throw an exception
md = GetNetworkResource();
}
catch (const networkIOException& e) {
// Code that executes when an exception of type
// networkIOException is thrown in the try block
// ...
// Log error message in the exception object
cerr << e.what();
}
catch (const myDataFormatException& e) {
// Code that handles another exception type
// ...
cerr << e.what();
}
Remarks
The code after the try clause is the guarded section of code. The throw expression
throws—that is, raises—an exception. The code block after the catch clause is the
exception handler. This is the handler that catches the exception that's thrown if the
types in the throw and catch expressions are compatible. For a list of rules that govern
type-matching in catch blocks, see How Catch Blocks are Evaluated. If the catch
statement specifies an ellipsis (...) instead of a type, the catch block handles every type
of exception. When you compile with the /EHa option, these can include C structured
exceptions and system-generated or application-generated asynchronous exceptions
such as memory protection, divide-by-zero, and floating-point violations. Because catch
blocks are processed in program order to find a matching type, an ellipsis handler must
be the last handler for the associated try block. Use catch(...) with caution; don't
allow a program to continue unless the catch block knows how to handle the specific
exception that is caught. Typically, a catch(...) block is used to log errors and perform
special cleanup before program execution is stopped.
A throw expression that has no operand rethrows the exception currently being
handled. We recommend this form when rethrowing the exception, because this
preserves the original exception's polymorphic type information. Such an expression
should only be used in a catch handler or in a function that's called from a catch
handler. The rethrown exception object is the original exception object, not a copy.
C++
try {
throw CSomeOtherException();
}
catch(...) {
// Catch all exceptions - dangerous!!!
// Respond (perhaps only partially) to the exception, then
// re-throw to pass the exception to some other handler
// ...
throw;
}
See also
Modern C++ best practices for exceptions and error handling
Keywords
Unhandled C++ Exceptions
__uncaught_exception
How Catch Blocks are Evaluated (C++)
Article • 08/03/2021
If the type of thrown exception is a class, which also has a base class (or classes), it can
be caught by handlers that accept base classes of the exception's type, as well as
references to bases of the exception's type. Note that when an exception is caught by a
reference, it is bound to the actual thrown exception object; otherwise, it is a copy
(much the same as an argument to a function).
A handler that can accept any type (using the ellipsis syntax).
A handler that accepts the same type as the exception object; because it is a copy,
const and volatile modifiers are ignored.
A handler that accepts a reference to the same type as the exception object.
A handler that accepts a reference to a const or volatile form of the same type
as the exception object.
A handler that accepts a base class of the same type as the exception object; since
it is a copy, const and volatile modifiers are ignored. The catch handler for a
base class must not precede the catch handler for the derived class.
A handler that accepts a reference to a base class of the same type as the
exception object.
The order in which catch handlers appear is significant, because handlers for a given
try block are examined in order of their appearance. For example, it is an error to place
the handler for a base class before the handler for a derived class. After a matching
catch handler is found, subsequent handlers are not examined. As a result, an ellipsis
catch handler must be the last handler for its try block. For example:
C++
// ...
try
{
// ...
}
catch( ... )
{
// Handle exception here.
}
// Error: the next two handlers are never examined.
catch( const char * str )
{
cout << "Caught exception: " << str << endl;
}
catch( CExcptClass E )
{
// Handle CExcptClass exception here.
}
In this example, the ellipsis catch handler is the only handler that is examined.
See also
Modern C++ best practices for exceptions and error handling
Exceptions and Stack Unwinding in C++
Article • 11/14/2022
In the C++ exception mechanism, control moves from the throw statement to the first
catch statement that can handle the thrown type. When the catch statement is reached,
all of the automatic variables that are in scope between the throw and catch statements
are destroyed in a process that is known as stack unwinding. In stack unwinding,
execution proceeds as follows:
1. Control reaches the try statement by normal sequential execution. The guarded
section in the try block is executed.
5. If a matching catch handler is found, and it catches by value, its formal parameter
is initialized by copying the exception object. If it catches by reference, the
parameter is initialized to refer to the exception object. After the formal parameter
is initialized, the process of unwinding the stack begins. This involves the
destruction of all automatic objects that were fully constructed—but not yet
destructed—between the beginning of the try block that is associated with the
catch handler and the throw site of the exception. Destruction occurs in reverse
order of construction. The catch handler is executed and the program resumes
execution after the last handler—that is, at the first statement or construct that is
not a catch handler. Control can only enter a catch handler through a thrown
exception, never through a goto statement or a case label in a switch statement.
C++
#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;
};
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;
}
/* Output:
Entering main
Created Dummy: M
Copy created Dummy: M
Entering FunctionA
Copy created Dummy: A
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
Exiting main.
*/
Exception specifications (throw,
noexcept) (C++)
Article • 08/17/2021
Exception specifications are a C++ language feature that indicate the programmer's
intent about the exception types that can be propagated by a function. You can specify
that a function may or may not exit by an exception by using an exception specification.
The compiler can use this information to optimize calls to the function, and to terminate
the program if an unexpected exception escapes the function.
Prior to C++17 there were two kinds of exception specification. The noexcept
specification was new in C++11. It specifies whether the set of potential exceptions that
can escape the function is empty. The dynamic exception specification, or
throw(optional_type_list) specification, was deprecated in C++11 and removed in
C++17, except for throw() , which is an alias for noexcept(true) . This exception
specification was designed to provide summary information about what exceptions can
be thrown out of a function, but in practice it was found to be problematic. The one
dynamic exception specification that did prove to be somewhat useful was the
unconditional throw() specification. For example, the function declaration:
C++
tells the compiler that the function does not throw any exceptions. However, in
/std:c++14 mode this could lead to undefined behavior if the function does throw an
exception. Therefore we recommend using the noexcept operator instead of the one
above:
C++
Exception Meaning
specification
Exception Meaning
specification
noexcept The function does not throw an exception. In /std:c++14 mode (which is the
noexcept(true) default), noexcept and noexcept(true) are equivalent. When an exception is
throw() thrown from a function that is declared noexcept or noexcept(true) ,
std::terminate is invoked. When an exception is thrown from a function
declared as throw() in /std:c++14 mode, the result is undefined behavior. No
specific function is invoked. This is a divergence from the C++14 standard,
which required the compiler to invoke std::unexpected.
Visual Studio 2017 version 15.5 and later: In /std:c++17 mode , noexcept ,
noexcept(true) , and throw() are all equivalent. In /std:c++17 mode, throw()
is an alias for noexcept(true) . In /std:c++17 mode and later, when an
exception is thrown from a function declared with any of these specifications,
std::terminate is invoked as required by the C++17 standard.
throw(type) (C++14 and earlier) The function can throw an exception of type type . The
compiler accepts the syntax, but interprets it as noexcept(false) . In
/std:c++17 mode and later, the compiler issues warning C5040.
If exception handling is used in an application, there must be a function in the call stack
that handles thrown exceptions before they exit the outer scope of a function marked
noexcept , noexcept(true) , or throw() . If any functions called between the one that
throws an exception and the one that handles the exception are specified as noexcept ,
noexcept(true) (or throw() in /std:c++17 mode), the program is terminated when the
The following table summarizes whether a C++ function may potentially throw under
various compiler exception handling options:
Function /EHsc /EHs /EHa /EHac
C++ function with noexcept(false) , throw(...) , or throw(type) Yes Yes Yes Yes
exception specification
Example
C++
// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>
void handler() {
printf_s("in handler\n");
}
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
See also
try, throw, and catch Statements (C++)
Modern C++ best practices for exceptions and error handling
noexcept (C++)
Article • 09/28/2022
Syntax
noexcept-specifier :
noexcept
noexcept-expression
throw ( )
noexcept-expression :
noexcept ( constant-expression )
Parameters
constant-expression
A constant expression of type bool that represents whether the set of potential
exception types is empty. The unconditional version is equivalent to noexcept(true) .
Remarks
A noexcept-expression is a kind of exception specification: a suffix to a function
declaration that represents a set of types that might be matched by an exception
handler for any exception that exits a function. Unary conditional operator
noexcept(constant_expression) when constant_expression yields true , and its
unconditional synonym noexcept , specify that the set of potential exception types that
can exit a function is empty. That is, the function never throws an exception and never
allows an exception to be propagated outside its scope. The operator
noexcept(constant_expression) when constant_expression yields false , or the absence
Mark a function as noexcept only if all the functions that it calls, either directly or
indirectly, are also noexcept or const . The compiler doesn't necessarily check every
code path for exceptions that might bubble up to a noexcept function. If an exception
does exit the outer scope of a function marked noexcept , std::terminate is invoked
immediately, and there's no guarantee that destructors of any in-scope objects will be
invoked. Use noexcept instead of the dynamic exception specifier throw() . The dynamic
exception specification, or throw(optional_type_list) specification, was deprecated in
C++11 and removed in C++17, except for throw() , which is an alias for noexcept(true) .
We recommended you apply noexcept to any function that never allows an exception to
propagate up the call stack. When a function is declared noexcept , it enables the
compiler to generate more efficient code in several different contexts. For more
information, see Exception specifications.
Example
A function template that copies its argument might be declared noexcept on the
condition that the object being copied is a plain old data type (POD). Such a function
could be declared like this:
C++
#include <type_traits>
See also
Modern C++ best practices for exceptions and error handling
Exception specifications (throw, noexcept)
Unhandled C++ exceptions
Article • 08/03/2021
If a matching handler (or ellipsis catch handler) cannot be found for the current
exception, the predefined terminate run-time function is called. (You can also explicitly
call terminate in any of your handlers.) The default action of terminate is to call abort .
If you want terminate to call some other function in your program before exiting the
application, call the set_terminate function with the name of the function to be called
as its single argument. You can call set_terminate at any point in your program. The
terminate routine always calls the last function given as an argument to set_terminate .
Example
The following example throws a char * exception, but does not contain a handler
designated to catch exceptions of type char * . The call to set_terminate instructs
terminate to call term_func .
C++
// exceptions_Unhandled_Exceptions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void term_func() {
cout << "term_func was called by terminate." << endl;
exit( -1 );
}
int main() {
try
{
set_terminate( term_func );
throw "Out of memory!"; // No catch handler for this exception
}
catch( int )
{
cout << "Integer exception raised." << endl;
}
return 0;
}
Output
Output
term_func was called by terminate.
The term_func function should terminate the program or current thread, ideally by
calling exit . If it doesn't, and instead returns to its caller, abort is called.
See also
Modern C++ best practices for exceptions and error handling
Mixing C (structured) and C++
exceptions
Article • 08/03/2021
If you want to write portable code, the use of structured exception handling (SEH) in a
C++ program isn't recommended. However, you may sometimes want to compile using
/EHa and mix structured exceptions and C++ source code, and need some facility for
handling both kinds of exceptions. Because a structured exception handler has no
concept of objects or typed exceptions, it can't handle exceptions thrown by C++ code.
However, C++ catch handlers can handle structured exceptions. C++ exception
handling syntax ( try , throw , catch ) isn't accepted by the C compiler, but structured
exception handling syntax ( __try , __except , __finally ) is supported by the C++
compiler.
If you mix structured and C++ exceptions, be aware of these potential issues:
C++ exceptions and structured exceptions can't be mixed within the same
function.
C++ exception handling can catch and preserve the unwind semantics in all
modules compiled with the /EH compiler options, which enable unwind semantics.
There may be some situations in which destructor functions aren't called for all
objects. For example, a structured exception could occur while attempting to make
a function call through an uninitialized function pointer. If the function parameters
are objects constructed before the call, the destructors of those objects don't get
called during stack unwind.
Next steps
Using setjmp or longjmp in C++ programs
See more information on the use of setjmp and longjmp in C++ programs.
See also
Modern C++ best practices for exceptions and error handling
Using setjmp and longjmp
Article • 08/03/2021
When setjmp and longjmp are used together, they provide a way to execute a non-local
goto . They are typically used in C code to pass execution control to error-handling or
recovery code in a previously called routine without using the standard calling or return
conventions.
U Caution
Because setjmp and longjmp don't support correct destruction of stack frame
objects portably between C++ compilers, and because they might degrade
performance by preventing optimization on local variables, we don't recommend
their use in C++ programs. We recommend you use try and catch constructs
instead.
If you decide to use setjmp and longjmp in a C++ program, also include <setjmp.h> or
<setjmpex.h> to assure correct interaction between the functions and Structured
Exception Handling (SEH) or C++ exception handling.
Microsoft Specific
If you use an /EH option to compile C++ code, destructors for local objects are called
during the stack unwind. However, if you use /EHs or /EHsc to compile, and one of your
functions that uses noexcept calls longjmp , then the destructor unwind for that function
might not occur, depending on the optimizer state.
See also
Mixing C (Structured) and C++ Exceptions
Handle structured exceptions in C++
Article • 08/03/2021
The major difference between C structured exception handling (SEH) and C++ exception
handling is that the C++ exception handling model deals in types, while the C
structured exception handling model deals with exceptions of one type; specifically,
unsigned int . That is, C exceptions are identified by an unsigned integer value, whereas
C++ exceptions are identified by data type. When a structured exception is raised in C,
each possible handler executes a filter that examines the C exception context and
determines whether to accept the exception, pass it to some other handler, or ignore it.
When an exception is thrown in C++, it may be of any type.
When you use the /EHs or /EHsc compiler option, no C++ exception handlers handle
structured exceptions. These exceptions are handled only by __except structured
exception handlers or __finally structured termination handlers. For information, see
Structured Exception Handling (C/C++).
Under the /EHa compiler option, if a C exception is raised in a C++ program, it can be
handled by a structured exception handler with its associated filter or by a C++ catch
handler, whichever is dynamically nearer to the exception context. For example, this
sample C++ program raises a C exception inside a C++ try context:
// exceptions_Exception_Handling_Differences.cpp
// compile with: /EHa
#include <iostream>
int main() {
try {
SEHFunc();
}
catch( ... ) {
cout << "Caught a C exception."<< endl;
}
}
void SEHFunc() {
__try {
int x, y = 0;
x = 5 / y;
}
__finally {
cout << "In finally." << endl;
}
}
Output
In finally.
Caught a C exception.
Your wrapper class might have an interface consisting of some member functions that
determine the value of the exception, and that access the extended exception context
information provided by the C exception model. You might also want to define a default
constructor and a constructor that accepts an unsigned int argument (to provide for
the underlying C exception representation), and a bitwise copy constructor. Here is a
possible implementation of a C exception wrapper class:
C++
// exceptions_Exception_Handling_Differences2.cpp
// compile with: /c
class SE_Exception {
private:
SE_Exception() {}
SE_Exception( SE_Exception& ) {}
unsigned int nSE;
public:
SE_Exception( unsigned int n ) : nSE( n ) {}
~SE_Exception() {}
unsigned int getSeNumber() {
return nSE;
}
};
To use this class, install a custom C exception translation function that is called by the
internal exception handling mechanism each time a C exception is thrown. Within your
translation function, you can throw any typed exception (perhaps an SE_Exception type,
or a class type derived from SE_Exception ) that can be caught by an appropriate
matching C++ catch handler. The translation function can instead return, which
indicates that it did not handle the exception. If the translation function itself raises a C
exception, terminate is called.
To specify a custom translation function, call the _set_se_translator function with the
name of your translation function as its single argument. The translation function that
you write is called once for each function invocation on the stack that has try blocks.
There is no default translation function; if you do not specify one by calling
_set_se_translator, the C exception can only be caught by an ellipsis catch handler.
C++
// exceptions_Exception_Handling_Differences3.cpp
// compile with: /EHa
#include <stdio.h>
#include <eh.h>
#include <windows.h>
class SE_Exception {
private:
SE_Exception() {}
unsigned int nSE;
public:
SE_Exception( SE_Exception& e) : nSE(e.nSE) {}
SE_Exception(unsigned int n) : nSE(n) {}
~SE_Exception() {}
unsigned int getSeNumber() { return nSE; }
};
void SEFunc() {
__try {
int x, y = 0;
x = 5 / y;
}
__finally {
printf_s( "In finally\n" );
}
}
int main() {
_set_se_translator( trans_func );
try {
SEFunc();
}
catch( SE_Exception e ) {
printf_s( "Caught a __try exception with SE_Exception.\n" );
printf_s( "nSE = 0x%x\n", e.getSeNumber() );
}
}
Output
In trans_func.
In finally
Caught a __try exception with SE_Exception.
nSE = 0xc0000094
See also
Mixing C (Structured) and C++ exceptions
Structured Exception Handling (C/C++)
Article • 02/09/2023
Microsoft-specific:
Grammar
try-except-statement :
__try compound-statement __except ( filter-expression ) compound-statement
try-finally-statement :
__try compound-statement __finally compound-statement
Remarks
With SEH, you can ensure that resources, such as memory blocks and files, get released
correctly if execution unexpectedly terminates. You can also handle specific problems—
for example, insufficient memory—by using concise structured code that doesn't rely on
goto statements or elaborate testing of return codes.
The try-except and try-finally statements referred to in this article are Microsoft
extensions to the C and C++ languages. They support SEH by enabling applications to
gain control of a program after events that would otherwise terminate execution.
Although SEH works with C++ source files, it's not specifically designed for C++. If you
use SEH in a C++ program that you compile by using the /EHa or /EHsc option,
destructors for local objects are called, but other execution behavior might not be what
you expect. For an illustration, see the example later in this article. In most cases, instead
of SEH we recommend that you use ISO-standard C++ exception handling. By using
C++ exception handling, you can ensure that your code is more portable, and you can
handle exceptions of any type.
If you have C code that uses SEH, you can mix it with C++ code that uses C++ exception
handling. For information, see Handle structured exceptions in C++.
There are two SEH mechanisms:
These two kinds of handlers are distinct, but are closely related through a process
known as unwinding the stack. When a structured exception occurs, Windows looks for
the most recently installed exception handler that's currently active. The handler can do
one of three things:
The exception handler that recognizes the exception may not be in the function that was
running when the exception occurred. It may be in a function much higher on the stack.
The currently running function and all other functions on the stack frame are
terminated. During this process, the stack is unwound. That is, local non-static variables
of terminated functions get cleared from the stack.
As it unwinds the stack, the operating system calls any termination handlers that you've
written for each function. By using a termination handler, you clean up resources that
otherwise would remain open because of an abnormal termination. If you've entered a
critical section, you can exit it in the termination handler. When the program is going to
shut down, you can do other housekeeping tasks such as closing and removing
temporary files.
Next steps
Writing an exception handler
C++
#include <stdio.h>
#include <Windows.h>
#include <exception>
class TestClass
{
public:
~TestClass()
{
printf("Destroying TestClass!\n");
}
};
int main()
{
__try
{
TestExceptions();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("Executing SEH __except block\n");
}
return 0;
}
If you use /EHsc to compile this code but the local test control macro CPPEX is
undefined, the TestClass destructor doesn't run. The output looks like this:
Output
If you use /EHsc to compile the code and CPPEX is defined by using /DCPPEX (so that a
C++ exception is thrown), the TestClass destructor runs, and the output looks like this:
Output
If you use /EHa to compile the code, the TestClass destructor executes whether an
exception was thrown using a standard C++ throw expression or by using SEH. That is,
whether CPPEX is defined or not. The output looks like this:
Output
END Microsoft-specific
See also
Exception handling
Keywords
<exception>
Errors and exception handling
Structured Exception Handling (Windows)
Writing an Exception Handler
Article • 08/03/2021
Exception handlers are typically used to respond to specific errors. You can use the
exception-handling syntax to filter out all exceptions other than those you know how to
handle. Other exceptions should be passed to other handlers (possibly in the run-time
library or the operating system) written to look for those specific exceptions.
Hardware exceptions
See also
Structured Exception Handling (C/C++)
try-except statement
Article • 08/03/2021
C++
// . . .
__try {
// guarded code
}
__except ( /* filter expression */ ) {
// termination code
}
// . . .
Grammar
try-except-statement :
__try compound-statement __except ( expression ) compound-statement
Remarks
The try-except statement is a Microsoft extension to the C and C++ languages. It
enables target applications to gain control when events occur that normally terminate
program execution. Such events are called structured exceptions, or exceptions for short.
The mechanism that deals with these exceptions is called structured exception handling
(SEH).
7 Note
Structured exception handling works with Win32 for both C and C++ source files.
However, it's not specifically designed for C++. You can ensure that your code is
more portable by using C++ exception handling. Also, C++ exception handling is
more flexible, in that it can handle exceptions of any type. For C++ programs, we
recommend you use native C++ exception-handling: try, catch, and throw
statements.
The compound statement after the __try clause is the body or guarded section. The
__except expression is also known as the filter expression. Its value determines how the
exception is handled. The compound statement after the __except clause is the
exception handler. The handler specifies the actions to take if an exception is raised
during execution of the body section. Execution proceeds as follows:
up the stack for a handler, first for containing try-except statements, then
for handlers with the next highest precedence.
The __except expression is evaluated as a C expression. It's limited to a single value, the
conditional-expression operator, or the comma operator. If more extensive processing is
required, the expression can call a routine that returns one of the three values listed
above.
It's not valid to jump into a __try statement, but valid to jump out of one. The
exception handler isn't called if a process is terminated in the middle of executing a
try-except statement.
For compatibility with previous versions, _try, _except, and _leave are synonyms for
__try , __except , and __leave unless compiler option /Za (Disable language extensions)
is specified.
A goto statement can also jump out of the guarded section, and it doesn't degrade
performance as it does in a try-finally statement. That's because stack unwinding
doesn't occur. However, we recommend that you use the __leave keyword rather than a
goto statement. The reason is because you're less likely to make a programming
C++
The pointer types PEXCEPTION_RECORD and PCONTEXT are defined in the include file
<winnt.h>, and _EXCEPTION_RECORD and _CONTEXT are defined in the include file
<excpt.h>
You can use GetExceptionCode within the exception handler. However, you can use
GetExceptionInformation only within the exception filter expression. The information it
points to is generally on the stack and is no longer available when control gets
transferred to the exception handler.
Example
C++
// exceptions_try_except_Statement.cpp
// Example of try-except and try-finally statements
#include <stdio.h>
#include <windows.h> // for EXCEPTION_ACCESS_VIOLATION
#include <excpt.h>
int main()
{
int* p = 0x00000000; // pointer to NULL
puts("hello");
__try
{
puts("in try");
__try
{
puts("in try");
*p = 13; // causes an access violation exception;
}
__finally
{
puts("in finally. termination: ");
puts(AbnormalTermination() ? "\tabnormal" : "\tnormal");
}
}
__except(filter(GetExceptionCode(), GetExceptionInformation()))
{
puts("in except");
}
puts("world");
}
Output
Output
hello
in try
in try
in filter.
caught AV as expected.
in finally. termination:
abnormal
in except
world
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Keywords
Writing an exception filter
Article • 08/03/2021
You can handle an exception either by jumping to the level of the exception handler or
by continuing execution. Instead of using the exception handler code to handle the
exception and falling through, you can use a filter expression to clean up the problem.
Then, by returning EXCEPTION_CONTINUE_EXECUTION (-1), you may resume normal flow
without clearing the stack.
7 Note
For example, the following code uses a function call in the filter expression: this function
handles the problem and then returns -1 to resume normal flow of control:
C++
// exceptions_Writing_an_Exception_Filter.cpp
#include <windows.h>
int main() {
int Eval_Exception( int );
__try {}
}
void ResetVars( int ) {}
int Eval_Exception ( int n_except ) {
if ( n_except != STATUS_INTEGER_OVERFLOW &&
n_except != STATUS_FLOAT_OVERFLOW ) // Pass on most exceptions
return EXCEPTION_CONTINUE_SEARCH;
It's a good idea to use a function call in the filter expression whenever filter needs to do
anything complex. Evaluating the expression causes execution of the function, in this
case, Eval_Exception .
Note the use of GetExceptionCode to determine the exception. This function must be
called inside the filter expression of the __except statement. Eval_Exception can't call
GetExceptionCode , but it must have the exception code passed to it.
This handler passes control to another handler unless the exception is an integer or
floating-point overflow. If it is, the handler calls a function ( ResetVars is only an
example, not an API function) to reset some global variables. The __except statement
block, which in this example is empty, can never be executed because Eval_Exception
never returns EXCEPTION_EXECUTE_HANDLER (1).
Using a function call is a good general-purpose technique for dealing with complex filter
expressions. Two other C language features that are useful are:
The conditional operator is frequently useful here. It can be used to check for a specific
return code and then return one of two different values. For example, the filter in the
following code recognizes the exception only if the exception is
STATUS_INTEGER_OVERFLOW :
C++
The purpose of the conditional operator in this case is mainly to provide clarity, because
the following code produces the same results:
C++
The conditional operator is more useful in situations where you might want the filter to
evaluate to -1, EXCEPTION_CONTINUE_EXECUTION .
The comma operator lets you execute multiple expressions in sequence. It then returns
the value of the last expression. For example, the following code stores the exception
code in a variable and then tests it:
C++
__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Raising software exceptions
Article • 08/03/2021
Some of the most common sources of program errors are not flagged as exceptions by
the system. For example, if you attempt to allocate a memory block but there is
insufficient memory, the run-time or API function does not raise an exception but
returns an error code.
However, you can treat any condition as an exception by detecting that condition in
your code and then reporting it by calling the RaiseException function. By flagging
errors this way, you can bring the advantages of structured exception handling to any
kind of run-time error.
Use exception-handling filters to test for the exception code you defined.
The <winerror.h> file shows the format for exception codes. To make sure that you do
not define a code that conflicts with an existing exception code, set the third most
significant bit to 1. The four most-significant bits should be set as shown in the
following table.
31- 11 These two bits describe the basic status of the code: 11 = error, 00 =
30 success, 01 = informational, 10 = warning.
You can set the first two bits to a setting other than 11 binary if you want, although the
"error" setting is appropriate for most exceptions. The important thing to remember is
to set bits 29 and 28 as shown in the previous table.
The resulting error code should therefore have the highest four bits set to hexadecimal
E. For example, the following definitions define exception codes that do not conflict with
any Windows exception codes. (You may, however, need to check which codes are used
by third-party DLLs.)
C++
After you have defined an exception code, you can use it to raise an exception. For
example, the following code raises the STATUS_INSUFFICIENT_MEM exception in response
to a memory allocation problem:
C++
If you want to simply raise an exception, you can set the last three parameters to 0. The
three last parameters are useful for passing additional information and setting a flag
that prevents handlers from continuing execution. See the RaiseException function in
the Windows SDK for more information.
In your exception-handling filters, you can then test for the codes you've defined. For
example:
C++
__try {
...
}
__except (GetExceptionCode() == STATUS_INSUFFICIENT_MEM ||
GetExceptionCode() == STATUS_FILE_BAD_FORMAT )
See also
Writing an exception handler
Structured exception handling (C/C++)
Hardware exceptions
Article • 08/03/2021
Most of the standard exceptions recognized by the operating system are hardware-
defined exceptions. Windows recognizes a few low-level software exceptions, but these
are usually best handled by the operating system.
Windows maps the hardware errors of different processors to the exception codes in
this section. In some cases, a processor may generate only a subset of these exceptions.
Windows preprocesses information about the exception and issues the appropriate
exception code.
The hardware exceptions recognized by Windows are summarized in the following table:
Many of the exceptions listed in the previous table are intended to be handled by
debuggers, the operating system, or other low-level code. With the exception of integer
and floating-point errors, your code should not handle these errors. Thus, you should
usually use the exception-handling filter to ignore exceptions (evaluate to 0). Otherwise,
you may prevent lower-level mechanisms from responding appropriately. You can,
however, take appropriate precautions against the potential effect of these low-level
errors by writing termination handlers.
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Restrictions on exception handlers
Article • 08/03/2021
The principal limitation to using exception handlers in code is that you can't use a goto
statement to jump into a __try statement block. Instead, you must enter the statement
block through normal flow of control. You can jump out of a __try statement block, and
you can nest exception handlers as you choose.
See also
Writing an exception handler
Structured Exception Handling (C/C++)
Writing a Termination Handler
Article • 08/03/2021
Cleaning up resources
See also
Structured Exception Handling (C/C++)
try-finally statement
Article • 04/10/2023
Syntax
The following syntax describes the try-finally statement:
C++
// . . .
__try {
// guarded code
}
__finally {
// termination code
}
// . . .
Grammar
try-finally-statement :
__try compound-statement __finally compound-statement
The try-finally statement is a Microsoft extension to the C and C++ languages that
enable target applications to guarantee execution of cleanup code when execution of a
block of code is interrupted. Cleanup consists of such tasks as deallocating memory,
closing files, and releasing file handles. The try-finally statement is especially useful
for routines that have several places where a check is made for an error that could cause
premature return from the routine.
For related information and a code sample, see try-except Statement. For more
information on structured exception handling in general, see Structured Exception
Handling. For more information on handling exceptions in managed applications with
C++/CLI, see Exception Handling under /clr.
7 Note
Structured exception handling works with Win32 for both C and C++ source files.
However, it is not specifically designed for C++. You can ensure that your code is
more portable by using C++ exception handling. Also, C++ exception handling is
more flexible, in that it can handle exceptions of any type. For C++ programs, it is
recommended that you use the C++ exception-handling mechanism (try, catch,
and throw statements).
The compound statement after the __try clause is the guarded section. The compound
statement after the __finally clause is the termination handler. The handler specifies a
set of actions that execute when the guarded section is exited, whether it exits the
guarded section by an exception (abnormal termination), or by standard fall through
(normal termination).
Control reaches a __try statement by simple sequential execution (fall through). When
control enters the __try , its associated handler becomes active. If the flow of control
reaches the end of the try block, execution proceeds as follows:
2. When the termination handler completes, execution continues after the __finally
statement. However the guarded section ends (for example, via a goto out of the
guarded body or a return statement), the termination handler is executed before
the flow of control moves out of the guarded section.
If an exception occurs in the __try block, the operating system must find a handler for
the exception, or the program will fail. If a handler is found, any and all __finally blocks
are executed and execution resumes in the handler.
For example, suppose a series of function calls links function A to function D, as shown
in the following figure. Each function has one termination handler. If an exception is
raised in function D and handled in A, the termination handlers are called in this order
as the system unwinds the stack: D, C, B.
Order of termination-handler execution
7 Note
The behavior of try-finally is different from some other languages that support the
use of finally , such as C#. A single __try may have either, but not both, of
__finally and __except . If both are to be used together, an outer try-except
statement must enclose the inner try-finally statement. The rules specifying when
each block executes are also different.
For compatibility with previous versions, _try , _finally , and _leave are synonyms for
__try , __finally , and __leave unless compiler option /Za (Disable language
extensions) is specified.
A goto statement can also jump out of the guarded section, but it degrades
performance because it invokes stack unwinding. The __leave statement is more
efficient because it doesn't cause stack unwinding.
Abnormal Termination
Exiting a try-finally statement using the longjmp run-time function is considered
abnormal termination. It isn't legal to jump into a __try statement, but it's legal to jump
out of one. All __finally statements that are active between the point of departure
(normal termination of the __try block) and the destination (the __except block that
handles the exception) must be run. It's called a local unwind.
If a __try block is prematurely terminated for any reason, including a jump out of the
block, the system executes the associated __finally block as a part of the process of
unwinding the stack. In such cases, the AbnormalTermination function returns true if
called from within the __finally block; otherwise, it returns false .
The termination handler isn't called if a process is killed in the middle of executing a
try-finally statement.
END Microsoft-specific
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Keywords
Termination-handler syntax
Cleaning up resources
Article • 08/03/2021
During termination-handler execution, you may not know which resources have been
acquired before the termination handler was called. It's possible that the __try
statement block was interrupted before all resources were acquired, so that not all
resources were opened.
To be safe, you should check to see which resources are open before proceeding with
termination-handling cleanup. A recommended procedure is to:
2. In the __try statement block, acquire resources. Handles are set to positive values
as the resource is acquired.
Example
For example, the following code uses a termination handler to close three files and
release a memory block. These resources were acquired in the __try statement block.
Before cleaning up a resource, the code first checks to see if the resource was acquired.
C++
// exceptions_Cleaning_up_Resources.cpp
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
void fileOps() {
FILE *fp1 = NULL,
*fp2 = NULL,
*fp3 = NULL;
LPVOID lpvoid = NULL;
errno_t err;
__try {
lpvoid = malloc( BUFSIZ );
int main() {
fileOps();
}
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Timing of exception handling: A
summary
Article • 08/03/2021
7 Note
The Microsoft C++ compiler supports two forms of the setjmp and longjmp
statements. The fast version bypasses termination handling but is more efficient. To
use this version, include the file <setjmp.h>. The other version supports
termination handling as described in the previous paragraph. To use this version,
include the file <setjmpex.h>. The increase in performance of the fast version
depends on hardware configuration.
The operating system executes all termination handlers in the proper order before any
other code can be executed, including the body of an exception handler.
When the cause for interruption is an exception, the system must first execute the filter
portion of one or more exception handlers before deciding what to terminate. The order
of events is:
1. An exception is raised.
2. The system looks at the hierarchy of active exception handlers and executes the
filter of the handler with highest precedence. That's the exception handler most
recently installed and most deeply nested, going by blocks and function calls.
3. If this filter passes control (returns 0), the process continues until a filter is found
that doesn't pass control.
4. If this filter returns -1, execution continues where the exception was raised, and no
termination takes place.
The system unwinds the stack: It clears all stack frames between where the
exception was raised and the stack frame that contains the exception handler.
As the stack is unwound, each termination handler on the stack is executed.
Control passes to the line of code after the end of this exception handler.
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Restrictions on Termination Handlers
Article • 08/03/2021
You can't use a goto statement to jump into a __try statement block or a __finally
statement block. Instead, you must enter the statement block through normal flow of
control. (You can, however, jump out of a __try statement block.) Also, you can't nest
an exception handler or termination handler inside a __finally block.
unusual happens. But if the system is unwinding the stack, that unwinding stops. Then,
the current function gains control as if there were no abnormal termination.
A return statement inside a __finally statement block presents roughly the same
situation. Control returns to the immediate caller of the function that contains the
termination handler. If the system was unwinding the stack, this process is halted. Then,
the program proceeds as if no exception had been raised.
See also
Writing a termination handler
Structured Exception Handling (C/C++)
Transporting exceptions between
threads
Article • 05/02/2023
The Microsoft C++ compiler (MSVC) supports transporting an exception from one thread
to another. Transporting exceptions enables you to catch an exception in one thread
and then make the exception appear to be thrown in a different thread. For example,
you can use this feature to write a multithreaded application where the primary thread
handles all the exceptions thrown by its secondary threads. Transporting exceptions is
useful mostly to developers who create parallel programming libraries or systems. To
implement transporting exceptions, MSVC provides the exception_ptr type and the
current_exception, rethrow_exception, and make_exception_ptr functions.
Syntax
C++
namespace std
{
typedef unspecified exception_ptr;
exception_ptr current_exception();
void rethrow_exception(exception_ptr p);
template<class E>
exception_ptr make_exception_ptr(E e) noexcept;
}
Parameters
unspecified
An unspecified internal class that is used to implement the exception_ptr type.
Remarks
Scenario
Imagine that you want to create an application that can scale to handle a variable
amount of work. To achieve this objective, you design a multithreaded application where
an initial, primary thread creates as many secondary threads as it needs in order to do
the job. The secondary threads help the primary thread to manage resources, to balance
loads, and to improve throughput. By distributing the work, the multithreaded
application performs better than a single-threaded application.
However, if a secondary thread throws an exception, you want the primary thread to
handle it. This is because you want your application to handle exceptions in a consistent,
unified manner regardless of the number of secondary threads.
Solution
To handle the previous scenario, the C++ Standard supports transporting an exception
between threads. If a secondary thread throws an exception, that exception becomes
the current exception. By analogy to the real world, the current exception is said to be in
flight. The current exception is in flight from the time it's thrown until the exception
handler that catches it returns.
The secondary thread can catch the current exception in a catch block, and then call the
current_exception function to store the exception in an exception_ptr object. The
exception_ptr object must be available to the secondary thread and to the primary
thread. For example, the exception_ptr object can be a global variable whose access is
controlled by a mutex. The term transport an exception means an exception in one
thread can be converted to a form that can be accessed by another thread.
Next, the primary thread calls the rethrow_exception function, which extracts and then
throws the exception from the exception_ptr object. When the exception is thrown, it
becomes the current exception in the primary thread. That is, the exception appears to
originate in the primary thread.
Finally, the primary thread can catch the current exception in a catch block and then
process it or throw it to a higher level exception handler. Or, the primary thread can
ignore the exception and allow the process to end.
Most applications don't have to transport exceptions between threads. However, this
feature is useful in a parallel computing system because the system can divide work
among secondary threads, processors, or cores. In a parallel computing environment, a
single, dedicated thread can handle all the exceptions from the secondary threads and
can present a consistent exception-handling model to any application.
For more information about the C++ Standards committee proposal, search the Internet
for document number N2179, titled "Language Support for Transporting Exceptions
between Threads".
Only the following combination of compiler options and programming statements can
transport an exception. Other combinations either can't catch exceptions, or can catch
but can't transport exceptions.
The /EHa compiler option and the catch statement can transport SEH and C++
exceptions.
The /EHa , /EHs , and /EHsc compiler options and the catch statement can
transport C++ exceptions.
The /clr compiler option and the catch statement can transport C++ exceptions.
The /clr compiler option implies specification of the /EHa option. The compiler
doesn't support transporting managed exceptions. This is because managed
exceptions, which are derived from the System.Exception class, are already objects
that you can move between threads by using the facilities of the common
language runtime.
) Important
We recommend that you specify the /EHsc compiler option and catch only
C++ exceptions. You expose yourself to a security threat if you use the /EHa
or /clr compiler option and a catch statement with an ellipsis exception-
declaration ( catch(...) ). You probably intend to use the catch statement to
capture a few specific exceptions. However, the catch(...) statement
captures all C++ and SEH exceptions, including unexpected ones that should
be fatal. If you ignore or mishandle an unexpected exception, malicious code
can use that opportunity to undermine the security of your program.
Usage
The following sections describe how to transport exceptions by using the exception_ptr
type, and the current_exception , rethrow_exception , and make_exception_ptr functions.
exception_ptr type
Use an exception_ptr object to reference the current exception or an instance of a user-
specified exception. In the Microsoft implementation, an exception is represented by an
EXCEPTION_RECORD structure. Each exception_ptr object includes an exception
reference field that points to a copy of the EXCEPTION_RECORD structure that represents
the exception.
When you declare an exception_ptr variable, the variable isn't associated with any
exception. That is, its exception reference field is NULL. Such an exception_ptr object is
called a null exception_ptr.
Comparisons
You can use the equal ( == ) and not-equal ( != ) operators to compare two exception_ptr
objects. The operators don't compare the binary value (bit pattern) of the
EXCEPTION_RECORD structures that represent the exceptions. Instead, the operators
compare the addresses in the exception reference field of the exception_ptr objects. So,
a null exception_ptr and the NULL value compare as equal.
current_exception function
Call the current_exception function in a catch block. If an exception is in flight and the
catch block can catch the exception, the current_exception function returns an
exception_ptr object that references the exception. Otherwise, the function returns a
Details
The current_exception function captures the exception that is in flight regardless of
whether the catch statement specifies an exception-declaration statement.
The destructor for the current exception is called at the end of the catch block if you
don't rethrow the exception. However, even if you call the current_exception function in
the destructor, the function returns an exception_ptr object that references the current
exception.
SEH exceptions
If you use the /EHa compiler option, you can catch an SEH exception in a C++ catch
block. The current_exception function returns an exception_ptr object that references
the SEH exception. And the rethrow_exception function throws the SEH exception if you
call it with the transported exception_ptr object as its argument.
If you catch an SEH exception, you must manage the memory referenced by any pointer
in the EXCEPTION_RECORD.ExceptionInformation data member array. You must guarantee
that the memory is valid during the lifetime of the corresponding exception_ptr object,
and that the memory is freed when the exception_ptr object is deleted.
You can use structured exception (SE) translator functions together with the transport
exceptions feature. If an SEH exception is translated to a C++ exception, the
current_exception function returns an exception_ptr that references the translated
exception instead of the original SEH exception. The rethrow_exception function throws
the translated exception, not the original exception. For more information about SE
translator functions, see _set_se_translator.
rethrow_exception function
After you store a caught exception in an exception_ptr object, the primary thread can
process the object. In your primary thread, call the rethrow_exception function together
with the exception_ptr object as its argument. The rethrow_exception function extracts
the exception from the exception_ptr object and then throws the exception in the
context of the primary thread. If the p parameter of the rethrow_exception function is a
null exception_ptr , the function throws std::bad_exception.
The extracted exception is now the current exception in the primary thread, and you can
handle it as you would any other exception. If you catch the exception, you can handle it
immediately or use a throw statement to send it to a higher level exception handler.
Otherwise, do nothing and let the default system exception handler terminate your
process.
make_exception_ptr function
The make_exception_ptr function takes an instance of a class as its argument and then
returns an exception_ptr that references the instance. Usually, you specify an exception
class object as the argument to the make_exception_ptr function, although any class
object can be the argument.
Example
The following example transports a standard C++ exception and a custom C++
exception from one thread to another.
C++
// transport_exception.cpp
// compile with: /EHsc /MD
#include <windows.h>
#include <stdio.h>
#include <exception>
#include <stdexcept>
Output
Requirements
Header: <exception>
See also
Exception Handling /EH (Exception Handling Model)
/clr (Common Language Runtime Compilation)