0% found this document useful (0 votes)
36 views79 pages

C++ 16 Exception Handling

Uploaded by

btech10253.19
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views79 pages

C++ 16 Exception Handling

Uploaded by

btech10253.19
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 79

Exception handling in MSVC

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:

C++ 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.

Structured exception handling

Windows supplies its own exception mechanism, called structured exception


handling (SEH). It's not recommended for C++ or MFC programming. Use SEH
only in non-MFC C programs.

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

How to design for exception safety

How to interface between exceptional and non-exceptional code

The try, catch, and throw Statements

How Catch Blocks are Evaluated

Exceptions and Stack Unwinding

Exception Specifications

noexcept

Unhandled C++ Exceptions

Mixing C (Structured) and C++ Exceptions

Structured Exception Handling (SEH) (C/C++)

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.

Use exceptions for exceptional code


Program errors are often divided into two categories:

Logic errors caused by programming mistakes. For example, an "index out of


range" error.
Runtime errors that are beyond the control of programmer. For example, a
"network service unavailable" error.

In C-style programming and in COM, error reporting is managed either by returning a


value that represents an error code or a status code for a particular function, or by
setting a global variable that the caller may optionally retrieve after every function call
to see whether errors were reported. For example, COM programming uses the HRESULT
return value to communicate errors to the caller. And the Win32 API has the
GetLastError function to retrieve the last error reported by the call stack. In both of

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.

Exceptions are preferred in modern C++ for the following reasons:

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>

using namespace std;

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.

Exceptions and performance


The exception mechanism has a minimal performance cost if no exception is thrown. If
an exception is thrown, the cost of the stack traversal and unwinding is roughly
comparable to the cost of a function call. Other data structures are required to track the
call stack after a try block is entered, and more instructions are required to unwind the
stack if an exception is thrown. However, in most scenarios, the cost in performance and
memory footprint isn't significant. The adverse effect of exceptions on performance is
likely to be significant only on memory-constrained systems. Or, in performance-critical
loops, where an error is likely to occur regularly and there's tight coupling between the
code to handle it and the code that reports it. In any case, it's impossible to know the
actual cost of exceptions without profiling and measuring. Even in those rare cases when
the cost is significant, you can weigh it against the increased correctness, easier
maintainability, and other advantages that are provided by a well-designed exception
policy.

Exceptions versus assertions


Exceptions and asserts are two distinct mechanisms for detecting run-time errors in a
program. Use assert statements to test for conditions during development that should
always be true or always be false if all your code is correct. There's no point in handling
such an error by using an exception, because the error indicates that something in the
code has to be fixed. It doesn't represent a condition that the program has to recover
from at run time. An assert stops execution at the statement so that you can inspect
the program state in the debugger. An exception continues execution from the first
appropriate catch handler. Use exceptions to check error conditions that might occur at
run time even if your code is correct, for example, "file not found" or "out of memory."
Exceptions can handle these conditions, even if the recovery just outputs a message to a
log and ends the program. Always check arguments to public functions by using
exceptions. Even if your function is error-free, you might not have complete control over
arguments that a user might pass to it.

C++ exceptions versus Windows SEH


exceptions
Both C and C++ programs can use the structured exception handling (SEH) mechanism
in the Windows operating system. The concepts in SEH resemble the ones in C++
exceptions, except that SEH uses the __try , __except , and __finally constructs instead
of try and catch . In the Microsoft C++ compiler (MSVC), C++ exceptions are
implemented for SEH. However, when you write C++ code, use the C++ exception
syntax.

For more information about SEH, see Structured Exception Handling (C/C++).

Exception specifications and noexcept


Exception specifications were introduced in C++ as a way to specify the exceptions that
a function might throw. However, exception specifications proved problematic in
practice, and are deprecated in the C++11 draft standard. We recommend that you
don't use throw exception specifications except for throw() , which indicates that the
function allows no exceptions to escape. If you must use exception specifications of the
deprecated form throw( type-name ) , MSVC support is limited. For more information,
see Exception Specifications (throw). The noexcept specifier is introduced in C++11 as
the preferred alternative to throw() .

See also
How to: Interface between exceptional and non-exceptional code
C++ language reference
C++ Standard Library

Feedback
Was this page helpful?  Yes  No

Provide product feedback | Get help at Microsoft Q&A


How to: Design for exception safety
Article • 08/03/2021

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.

No matter how a function handles an exception, to help guarantee that it is "exception-


safe," it must be designed according to the following basic rules.

Keep resource classes simple


When you encapsulate manual resource management in classes, use a class that does
nothing except manage a single resource. By keeping the class simple, you reduce the
risk of introducing resource leaks. Use smart pointers when possible, as shown in the
following example. This example is intentionally artificial and simplistic to highlight the
differences when shared_ptr is used.

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>

using namespace std;

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.
};

// A more powerful case for shared_ptr

class Shape {
// ...
};

class Circle : public Shape {


// ...
};

class Triangle : public Shape {


// ...
};

class SPShapeResourceClass {
private:
shared_ptr<Shape> m_p;
shared_ptr<Shape> m_q;
public:
SPShapeResourceClass() : m_p(new Circle), m_q(new Triangle) { }
};

Use the RAII idiom to manage resources


To be exception-safe, a function must ensure that objects that it has allocated by using
malloc or new are destroyed, and all resources such as file handles are closed or

released even if an exception is thrown. The Resource Acquisition Is Initialization (RAII)


idiom ties management of such resources to the lifespan of automatic variables. When a
function goes out of scope, either by returning normally or because of an exception, the
destructors for all fully-constructed automatic variables are invoked. An RAII wrapper
object such as a smart pointer calls the appropriate delete or close function in its
destructor. In exception-safe code, it is critically important to pass ownership of each
resource immediately to some kind of RAII object. Note that the vector , string ,
make_shared , fstream , and similar classes handle acquisition of the resource for you.

However, unique_ptr and traditional shared_ptr constructions are special because


resource acquisition is performed by the user instead of the object; therefore, they
count as Resource Release Is Destruction but are questionable as RAII.

The three exception guarantees


Typically, exception safety is discussed in terms of the three exception guarantees that a
function can provide: the no-fail guarantee, the strong guarantee, and the basic
guarantee.

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.

Understand that an exception thrown in a base class constructor cannot be


swallowed in a derived class constructor. If you want to translate and re-throw the
base class exception in a derived constructor, use a function try block.

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.

Call non-exceptional functions from C++


When you call a non-exceptional function from C++, the idea is to wrap that function in
a C++ function that detects any errors and then possibly throws an exception. When
you design such a wrapper function, first decide which type of exception guarantee to
provide: noexcept, strong, or basic. Second, design the function so that all resources, for
example, file handles, are correctly released if an exception is thrown. Typically, it means
that you use smart pointers or similar resource managers to own the resources. For
more information about design considerations, see How to: Design for exception safety.

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++

// compile with: /EHsc


#include <Windows.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <string>
#include <limits>
#include <stdexcept>

using namespace std;

string FormatErrorMessage(DWORD error, const string& msg)


{
static const int BUFFERLENGTH = 1024;
vector<char> buf(BUFFERLENGTH);
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, buf.data(),
BUFFERLENGTH - 1, 0);
return string(buf.data()) + " (" + msg + ")";
}

class Win32Exception : public runtime_error


{
private:
DWORD m_error;
public:
Win32Exception(DWORD error, const string& msg)
: runtime_error(FormatErrorMessage(error, msg)), m_error(error) { }

DWORD GetErrorCode() const { return m_error; }


};

void ThrowLastErrorIf(bool expression, const string& msg)


{
if (expression) {
throw Win32Exception(GetLastError(), msg);
}
}

class File
{
private:
HANDLE m_handle;

// Declared but not defined, to avoid double closing.


File& operator=(const File&);
File(const File&);
public:
explicit File(const string& filename)
{
m_handle = CreateFileA(filename.c_str(), GENERIC_READ,
FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, nullptr);
ThrowLastErrorIf(m_handle == INVALID_HANDLE_VALUE,
"CreateFile call failed on file named " + filename);
}

~File() { CloseHandle(m_handle); }

HANDLE GetHandle() { return m_handle; }


};

size_t GetFileSizeSafe(const string& filename)


{
File fobj(filename);
LARGE_INTEGER filesize;

BOOL result = GetFileSizeEx(fobj.GetHandle(), &filesize);


ThrowLastErrorIf(result == FALSE, "GetFileSizeEx failed: " + filename);

if (filesize.QuadPart < (numeric_limits<size_t>::max)()) {


return filesize.QuadPart;
} else {
throw;
}
}

vector<char> ReadFileVector(const string& filename)


{
File fobj(filename);
size_t filesize = GetFileSizeSafe(filename);
DWORD bytesRead = 0;

vector<char> readbuffer(filesize);

BOOL result = ReadFile(fobj.GetHandle(), readbuffer.data(),


readbuffer.size(),
&bytesRead, nullptr);
ThrowLastErrorIf(result == FALSE, "ReadFile failed: " + filename);

cout << filename << " file size: " << filesize << ", bytesRead: "
<< bytesRead << endl;

return readbuffer;
}

bool IsFileDiff(const string& filename1, const string& filename2)


{
return ReadFileVector(filename1) != ReadFileVector(filename2);
}
#include <iomanip>

int main ( int argc, char* argv[] )


{
string filename1("file1.txt");
string filename2("file2.txt");

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
}
}

Call exceptional code from non-exceptional


code
C++ functions that are declared as extern "C" can be called by C programs. C++ COM
servers can be consumed by code written in any number of different languages. When
you implement public exception-aware functions in C++ to be called by non-
exceptional code, the C++ function must not allow any exceptions to propagate back to
the caller. Such callers have no way to catch or handle C++ exceptions. The program
may terminate, leak resources, or cause undefined behavior.

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++

BOOL DiffFiles2(const string& file1, const string& file2)


{
try
{
File f1(file1);
File f2(file2);
if (IsTextFileDiff(f1, f2))
{
SetLastError(MY_APPLICATION_ERROR_FILE_MISMATCH);
return FALSE;
}
return TRUE;
}
catch(Win32Exception& e)
{
SetLastError(e.GetErrorCode());
}

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++

bool DiffFiles3(const string& file1, const string& file2)


{
return Win32ExceptionBoundary([&]() -> bool
{
File f1(file1);
File f2(file2);
if (IsTextFileDiff(f1, f2))
{
SetLastError(MY_APPLICATION_ERROR_FILE_MISMATCH);
return false;
}
return true;
});
}

For more information about lambda expressions, see Lambda expressions.

Call exceptional code through non-exceptional


code from exceptional code
It's possible, but not recommended, to throw exceptions across exception-unaware
code. For example, your C++ program may call a library that uses callback functions you
provide. In some circumstances, you can throw exceptions from the callback functions
across the non-exceptional code that your original caller can handle. However, the
circumstances when exceptions can work successfully are strict. You must compile the
library code in a way that preserves stack unwinding semantics. The exception-unaware
code can't do anything that might trap the C++ exception. Also, the library code
between the caller and the callback can't allocate local resources. For example, the code
that isn't exception-aware can't have locals that point to allocated heap memory. These
resources are leaked when the stack is unwound.

These requirements must be met to throw exceptions across non-exception-aware code:

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.

A throw expression signals that an exceptional condition—often, an error—has occurred


in a try block. You can use an object of any type as the operand of a throw expression.
Typically, this object is used to communicate information about the error. In most cases,
we recommend that you use the std::exception class or one of the derived classes that
are defined in the standard library. If one of those isn't appropriate, we recommend that
you derive your own exception class from std::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();
}

// The following syntax shows a throw expression


MyData GetNetworkResource()
{
// ...
if (IOSuccess == false)
throw networkIOException("Unable to connect");
// ...
if (readError)
throw myDataFormatException("Format error");
// ...
}

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

C++ enables you to throw exceptions of any type, although in general it is


recommended to throw types that are derived from std::exception. A C++ exception can
be caught by a catch handler that specifies the same type as the thrown exception, or
by a handler that can catch any type of exception.

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).

When an exception is thrown, it may be caught by the following types of catch


handlers:

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.

A handler that accepts a reference to a const or volatile form of a base class of


the same type as the exception object.

A handler that accepts a pointer to which a thrown pointer object can be


converted via standard pointer conversion rules.

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.

2. If no exception is thrown during execution of the guarded section, the catch


clauses that follow the try block are not executed. Execution continues at the
statement after the last catch clause that follows the associated try block.

3. If an exception is thrown during execution of the guarded section or in any routine


that the guarded section calls either directly or indirectly, an exception object is
created from the object that is created by the throw operand. (This implies that a
copy constructor may be involved.) At this point, the compiler looks for a catch
clause in a higher execution context that can handle an exception of the type that
is thrown, or for a catch handler that can handle any type of exception. The catch
handlers are examined in order of their appearance after the try block. If no
appropriate handler is found, the next dynamically enclosing try block is
examined. This process continues until the outermost enclosing try block is
examined.

4. If a matching handler is still not found, or if an exception occurs during the


unwinding process but before the handler gets control, the predefined run-time
function terminate is called. If an exception occurs after the exception is thrown
but before the unwind begins, terminate is called.

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.

Stack unwinding example


The following example demonstrates how the stack is unwound when an exception is
thrown. Execution on the thread jumps from the throw statement in C to the catch
statement in main , and unwinds each function along the way. Notice the order in which
the Dummy objects are created and then destroyed as they go out of scope. Also notice
that no function completes except main , which contains the catch statement. Function A
never returns from its call to B() , and B never returns from its call to C() . If you
uncomment the definition of the Dummy pointer and the corresponding delete
statement, and then run the program, notice that the pointer is never deleted. This
shows what can happen when functions do not provide an exception guarantee. For
more information, see How to: Design for Exceptions. If you comment out the catch
statement, you can observe what happens when a program terminates because of an
unhandled exception.

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;
};

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 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++

void MyFunction(int i) throw();

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++

void MyFunction(int i) noexcept;

The following table summarizes the Microsoft C++ implementation of exception


specifications:

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.

noexcept(false) The function can throw an exception of any type.


throw(...)
No specification

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

noexcept function propagates the exception.

The exception behavior of a function depends on the following factors:

Which language standard compilation mode is set.

Whether you are compiling the function under C or C++.

Which /EH compiler option you use.

Whether you explicitly specify the exception specification.

Explicit exception specifications are not allowed on C functions. A C function is assumed


not to throw exceptions under /EHsc , and may throw structured exceptions under /EHs ,
/EHa , or /EHac .

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 no exception specification Yes Yes Yes Yes

C++ function with noexcept , noexcept(true) , or throw() No No Yes Yes


exception specification

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");
}

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

See also
try, throw, and catch Statements (C++)
Modern C++ best practices for exceptions and error handling
noexcept (C++)
Article • 09/28/2022

C++11: Specifies whether a function might throw exceptions.

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

of an exception specification (other than for a destructor or deallocation function),


indicates that the set of potential exceptions that can exit the function is the set of all
types.

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>

template <typename T>


T copy_object(const T& obj) noexcept(std::is_pod<T>)
{
// ...
}

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.

See _set_se_translator for information on how to handle structured exceptions as C++


exceptions.

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.

Termination handlers ( __finally blocks) are always executed, even during


unwinding after an exception is thrown.

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.

Handle structured exceptions in C++


See examples of the ways you can use C++ to handle structured exceptions.

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.

In portable code, when a longjmp call is executed, correct destruction of frame-based


objects is explicitly not guaranteed by the standard, and may not be supported by other
compilers. To let you know, at warning level 4, a call to setjmp causes warning C4611:
interaction between '_setjmp' and C++ object destruction is non-portable.

END Microsoft Specific

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.

A second difference is that the C structured exception handling model is referred to as


asynchronous, because exceptions occur secondary to the normal flow of control. The
C++ exception handling mechanism is fully synchronous, which means that exceptions
occur only when they are thrown.

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:

Example - Catch a C exception in a C++ catch


block
C++

// exceptions_Exception_Handling_Differences.cpp
// compile with: /EHa
#include <iostream>

using namespace std;


void SEHFunc( void );

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.

C exception wrapper classes


In a simple example like the above, the C exception can be caught only by an ellipsis (...)
catch handler. No information about the type or nature of the exception is
communicated to the handler. While this method works, in some cases you may want to
define a transformation between the two exception handling models so that each C
exception is associated with a specific class. To transform one, you can define a C
exception "wrapper" class, which can be used or derived from in order to attribute a
specific class type to a C exception. By doing so, each C exception can be handled
separately by a specific C++ catch handler, instead of all of them in a single handler.

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.

Example - Use a custom translation function


For example, the following code installs a custom translation function, and then raises a
C exception that is wrapped by the SE_Exception class:

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" );
}
}

void trans_func( unsigned int u, _EXCEPTION_POINTERS* pExp ) {


printf_s( "In trans_func.\n" );
throw SE_Exception( u );
}

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

Structured exception handling (SEH) is a Microsoft extension to C and C++ to handle


certain exceptional code situations, such as hardware faults, gracefully. Although
Windows and Microsoft C++ support SEH, we recommend that you use ISO-standard
C++ exception handling in C++ code. It makes your code more portable and flexible.
However, to maintain existing code or for particular kinds of programs, you still might
have to use SEH.

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:

Exception handlers, or __except blocks, which can respond to or dismiss the


exception based on the filter-expression value. For more information, see try-
except statement.

Termination handlers, or __finally blocks, which are always called, whether an


exception causes termination or not. For more information, see try-finally
statement.

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:

Fail to recognize the exception and pass control to other handlers


( EXCEPTION_CONTINUE_SEARCH ).

Recognize the exception but dismiss it ( EXCEPTION_CONTINUE_EXECUTION ).

Recognize the exception and handle it ( EXCEPTION_EXECUTE_HANDLER ).

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

Writing a termination handler

Handle structured exceptions in C++


Example
As stated earlier, destructors for local objects are called if you use SEH in a C++
program and compile it by using the /EHa or /EHsc option. However, the behavior
during execution may not be what you expect if you're also using C++ exceptions. This
example demonstrates these behavioral differences.

C++

#include <stdio.h>
#include <Windows.h>
#include <exception>

class TestClass
{
public:
~TestClass()
{
printf("Destroying TestClass!\n");
}
};

__declspec(noinline) void TestCPPEX()


{
#ifdef CPPEX
printf("Throwing C++ exception\n");
throw std::exception("");
#else
printf("Triggering SEH exception\n");
volatile int *pInt = 0x00000000;
*pInt = 20;
#endif
}

__declspec(noinline) void TestExceptions()


{
TestClass d;
TestCPPEX();
}

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

Triggering SEH exception


Executing SEH __except block

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

Throwing C++ exception


Destroying TestClass!
Executing SEH __except block

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

Throwing C++ exception


Destroying TestClass!
Executing SEH __except block

For more information, see /EH (Exception Handling Model).

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.

Exception handlers use the try-except statement.

What do you want to know more about?


The try-except statement

Writing an exception filter

Raising software exceptions

Hardware exceptions

Restrictions on exception handlers

See also
Structured Exception Handling (C/C++)
try-except statement
Article • 08/03/2021

The try-except statement is a Microsoft-specific extension that supports structured


exception handling in the C and C++ languages.

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).

For related information, see the try-finally statement.

Exceptions may be either hardware-based or software-based. Structured exception


handling is useful even when applications can't completely recover from hardware or
software exceptions. SEH makes it possible to display error information and trap the
internal state of the application to help diagnose the problem. It's especially useful for
intermittent problems that aren't easy to reproduce.

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:

1. The guarded section is executed.

2. If no exception occurs during execution of the guarded section, execution


continues at the statement after the __except clause.

3. If an exception occurs during execution of the guarded section, or in any routine


the guarded section calls, the __except expression is evaluated. There are three
possible values:

EXCEPTION_CONTINUE_EXECUTION (-1) Exception is dismissed. Continue

execution at the point where the exception occurred.

EXCEPTION_CONTINUE_SEARCH (0) Exception isn't recognized. Continue to search

up the stack for a handler, first for containing try-except statements, then
for handlers with the next highest precedence.

EXCEPTION_EXECUTE_HANDLER (1) Exception is recognized. Transfer control to

the exception handler by executing the __except compound statement, then


continue execution after the __except block.

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.

Each application can have its own exception handler.

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.

The __leave keyword


The __leave keyword is valid only within the guarded section of a try-except
statement, and its effect is to jump to the end of the guarded section. Execution
continues at the first statement after the exception handler.

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

mistake if the guarded section is large or complex.

Structured exception handling intrinsic functions


Structured exception handling provides two intrinsic functions that are available to use
with the try-except statement: GetExceptionCode and GetExceptionInformation.

GetExceptionCode returns the code (a 32-bit integer) of the exception.

The intrinsic function GetExceptionInformation returns a pointer to an


EXCEPTION_POINTERS structure containing additional information about the exception.
Through this pointer, you can access the machine state that existed at the time of a
hardware exception. The structure is as follows:

C++

typedef struct _EXCEPTION_POINTERS {


PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

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.

The intrinsic function AbnormalTermination is available within a termination handler. It


returns 0 if the body of the try-finally statement terminates sequentially. In all other
cases, it returns 1.

<excpt.h> defines some alternate names for these intrinsics:

GetExceptionCode is equivalent to _exception_code

GetExceptionInformation is equivalent to _exception_info

AbnormalTermination is equivalent to _abnormal_termination

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 filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)


{
puts("in filter.");
if (code == EXCEPTION_ACCESS_VIOLATION)
{
puts("caught AV as expected.");
return EXCEPTION_EXECUTE_HANDLER;
}
else
{
puts("didn't catch AV, unexpected.");
return EXCEPTION_CONTINUE_SEARCH;
};
}

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

Some exceptions cannot be continued. If filter evaluates to -1 for such an


exception, the system raises a new exception. When you call RaiseException, you
determine whether the exception will continue.

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 {}

__except ( Eval_Exception( GetExceptionCode( ))) {


;
}

}
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;

// Execute some code to clean up problem


ResetVars( 0 ); // initializes data to 0
return EXCEPTION_CONTINUE_EXECUTION;
}

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

The comma operator

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++

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0 ) {

The purpose of the conditional operator in this case is mainly to provide clarity, because
the following code produces the same results:

C++

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ) {

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.

To use structured exception handling with errors:

Define your own exception code for the event.

Call RaiseException when you detect a problem.

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.

Bits Recommended Description


binary setting

31- 11 These two bits describe the basic status of the code: 11 = error, 00 =
30 success, 01 = informational, 10 = warning.

29 1 Client bit. Set to 1 for user-defined codes.

28 0 Reserved bit. (Leave set to 0.)

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++

#define STATUS_INSUFFICIENT_MEM 0xE0000001


#define STATUS_FILE_BAD_FORMAT 0xE0000002

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++

lpstr = _malloc( nBufferSize );


if (lpstr == NULL)
RaiseException( STATUS_INSUFFICIENT_MEM, 0, 0, 0);

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:

Exception code Cause of exception

STATUS_ACCESS_VIOLATION Reading or writing to an inaccessible memory


location.

STATUS_BREAKPOINT Encountering a hardware-defined breakpoint; used


only by debuggers.

STATUS_DATATYPE_MISALIGNMENT Reading or writing to data at an address that is not


properly aligned; for example, 16-bit entities must be
aligned on 2-byte boundaries. (Not applicable to
Intel 80x86 processors.)

STATUS_FLOAT_DIVIDE_BY_ZERO Dividing floating-point type by 0.0.

STATUS_FLOAT_OVERFLOW Exceeding maximum positive exponent of floating-


point type.

STATUS_FLOAT_UNDERFLOW Exceeding magnitude of lowest negative exponent of


floating-point type.

STATUS_FLOATING_RESEVERED_OPERAND Using a reserved floating-point format (invalid use of


format).

STATUS_ILLEGAL_INSTRUCTION Attempting to execute an instruction code not


defined by the processor.

STATUS_PRIVILEGED_INSTRUCTION Executing an instruction not allowed in current


machine mode.

STATUS_INTEGER_DIVIDE_BY_ZERO Dividing an integer type by 0.

STATUS_INTEGER_OVERFLOW Attempting an operation that exceeds the range of


the integer.
Exception code Cause of exception

STATUS_SINGLE_STEP Executing one instruction in single-step mode; used


only by debuggers.

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

Unlike an exception handler, a termination handler is always executed, regardless of


whether the protected block of code terminated normally. The sole purpose of the
termination handler should be to ensure that resources, such as memory, handles, and
files, are properly closed regardless of how a section of code finishes executing.

Termination handlers use the try-finally statement.

What do you want to know more about?


The try-finally statement

Cleaning up resources

Timing of actions in exception handling

Restrictions on termination handlers

See also
Structured Exception Handling (C/C++)
try-finally statement
Article • 04/10/2023

The try-finally statement is a Microsoft-specific extension that supports structured


exception handling in the C and C++ languages.

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:

1. The termination handler is invoked.

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.

A __finally statement doesn't block searching for an appropriate exception


handler.

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.

The __leave Keyword


The __leave keyword is valid only within the guarded section of a try-finally
statement, and its effect is to jump to the end of the guarded section. Execution
continues at the first statement in the termination handler.

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:

1. Initialize handles to NULL.

2. In the __try statement block, acquire resources. Handles are set to positive values
as the resource is acquired.

3. In the __finally statement block, release each resource whose corresponding


handle or flag variable is nonzero or not NULL.

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 );

err = fopen_s(&fp1, "ADDRESS.DAT", "w+" );


err = fopen_s(&fp2, "NAMES.DAT", "w+" );
err = fopen_s(&fp3, "CARS.DAT", "w+" );
}
__finally {
if ( fp1 )
fclose( fp1 );
if ( fp2 )
fclose( fp2 );
if ( fp3 )
fclose( fp3 );
if ( lpvoid )
free( lpvoid );
}
}

int main() {
fileOps();
}

See also
Writing a termination handler
Structured Exception Handling (C/C++)
Timing of exception handling: A
summary
Article • 08/03/2021

A termination handler is executed no matter how the __try statement block is


terminated. Causes include jumping out of the __try block, a longjmp statement that
transfers control out of the block, and unwinding the stack due to exception handling.

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.

5. If the filter returns 1, the following events occur:

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.

The exception handler itself 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.

Some kinds of code permitted in a termination handler produce questionable results, so


you should use them with caution, if at all. One is a goto statement that jumps out of a
__finally statement block. If the block executes as part of normal termination, nothing

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.

An exception_ptr object that references an exception.

A class that represents an exception.

An instance of the parameter E class.


Return value
The current_exception function returns an exception_ptr object that references the
exception that is currently in progress. If no exception is in progress, the function returns
an exception_ptr object that isn't associated with any exception.

The make_exception_ptr function returns an exception_ptr object that references the


exception specified by the e parameter.

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".

Exception-handling models and compiler options


Your application's exception-handling model determines whether it can catch and
transport an exception. Visual C++ supports three models for handling C++ exceptions:
ISO-standard C++ exception handling, structured exception handling (SEH), and
common language runtime (CLR) exceptions. Use the /EH and /clr compiler options to
specify your application's exception-handling model.

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.

Use the current_exception or make_exception_ptr function to assign an exception to an


exception_ptr object. When you assign an exception to an exception_ptr variable, the

variable's exception reference field points to a copy of the exception. If there is


insufficient memory to copy the exception, the exception reference field points to a
copy of a std::bad_alloc exception. If the current_exception or make_exception_ptr
function can't copy the exception for any other reason, the function calls the terminate
function to exit the current process.
Despite its name, an exception_ptr object isn't itself a pointer. It doesn't obey pointer
semantics and can't be used with the pointer member access ( -> ) or indirection ( * )
operators. The exception_ptr object has no public data members or member functions.

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

null exception_ptr object.

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.

Successive calls to the current_exception function return exception_ptr objects that


refer to different copies of the current exception. So, the objects compare as unequal
because they refer to different copies, even though the copies have the same binary
value.

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.

The current_exception function returns a null exception_ptr if you call it in an SEH


__finally termination handler, an __except exception handler, or the __except filter
expression.

A transported exception doesn't support nested exceptions. A nested exception occurs if


another exception is thrown while an exception is being handled. If you catch a nested
exception, the EXCEPTION_RECORD.ExceptionRecord data member points to a chain of
EXCEPTION_RECORD structures that describe the associated exceptions. The
current_exception function doesn't support nested exceptions because it returns an

exception_ptr object whose ExceptionRecord data member is zeroed out.

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.

Calling the make_exception_ptr function is equivalent to throwing a C++ exception,


catching it in a catch block, and then calling the current_exception function to return
an exception_ptr object that references the exception. The Microsoft implementation of
the make_exception_ptr function is more efficient than throwing and then catching an
exception.

An application typically doesn't require the make_exception_ptr function, and we


discourage its use.

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>

using namespace std;

// Define thread-specific information.


#define THREADCOUNT 2
exception_ptr aException[THREADCOUNT];
int aArg[THREADCOUNT];

DWORD WINAPI ThrowExceptions( LPVOID );

// Specify a user-defined, custom exception.


// As a best practice, derive your exception
// directly or indirectly from std::exception.
class myException : public std::exception {
};
int main()
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;

// Create secondary threads.


for( int i=0; i < THREADCOUNT; i++ )
{
aArg[i] = i;
aThread[i] = CreateThread(
NULL, // Default security attributes.
0, // Default stack size.
(LPTHREAD_START_ROUTINE) ThrowExceptions,
(LPVOID) &aArg[i], // Thread function argument.
0, // Default creation flags.
&ThreadID); // Receives thread identifier.
if( aThread[i] == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return -1;
}
}

// Wait for all threads to terminate.


WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread handles.
for( int i=0; i < THREADCOUNT; i++ ) {
CloseHandle(aThread[i]);
}

// Rethrow and catch the transported exceptions.


for ( int i = 0; i < THREADCOUNT; i++ ) {
try {
if (aException[i] == NULL) {
printf("exception_ptr %d: No exception was transported.\n",
i);
}
else {
rethrow_exception( aException[i] );
}
}
catch( const invalid_argument & ) {
printf("exception_ptr %d: Caught an invalid_argument
exception.\n", i);
}
catch( const myException & ) {
printf("exception_ptr %d: Caught a myException exception.\n",
i);
}
}
}
// Each thread throws an exception depending on its thread
// function argument, and then ends.
DWORD WINAPI ThrowExceptions( LPVOID lpParam )
{
int x = *((int*)lpParam);
if (x == 0) {
try {
// Standard C++ exception.
// This example explicitly throws invalid_argument exception.
// In practice, your application performs an operation that
// implicitly throws an exception.
throw invalid_argument("A C++ exception.");
}
catch ( const invalid_argument & ) {
aException[x] = current_exception();
}
}
else {
// User-defined exception.
aException[x] = make_exception_ptr( myException() );
}
return TRUE;
}

Output

exception_ptr 0: Caught an invalid_argument exception.


exception_ptr 1: Caught a myException exception.

Requirements
Header: <exception>

See also
Exception Handling /EH (Exception Handling Model)
/clr (Common Language Runtime Compilation)

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy