// Copyright 2006-2026 Emil Dotchevski and Reverge Studios, Inc.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
:last-update-label!:
:icons: font
:prewrap!:
:docinfo: shared
:stylesheet: zajo-dark.css
:source-highlighter: rouge
ifdef::backend-pdf[]
= Boost Exception
endif::[]
ifndef::backend-pdf[]
= Boost Exceptionpass:[
]
endif::[]
{CPP} Exception Augmentation Library | Emil Dotchevski
ifndef::backend-pdf[]
:toc: left
:toclevels: 3
:toc-title:
endif::[]
[[boost-exception]]
[cols="25,>75", grid=none, frame=none]
|===
|
|For {CPP}11 or newer, consider using https://www.boost.org/doc/libs/release/libs/leaf/doc/html/index.html[Boost LEAF]. It provides similar functionality more efficiently and understands Boost Exception for compatibility; see https://www.boost.org/doc/libs/release/libs/leaf/doc/html/index.html#boost_exception[this overview].
|===
== Introduction
The purpose of Boost Exception is to ease the design of exception class hierarchies and to help write exception handling and error reporting code.
It supports transporting of arbitrary data to the catch site, which is otherwise tricky due to the no-throw requirements (15.5.1) for exception types. Data can be added to any exception object, either directly in the throw-expression (15.1), or at a later time as the exception object propagates up the call stack.
The ability to add data to exception objects after they have been passed to throw is important, because often some of the information needed to handle an exception is unavailable in the context where the failure is detected.
Boost Exception also supports http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html[N2179]-style <> of exception objects, implemented non-intrusively and automatically by the `boost::<>` function.
ifndef::backend-pdf[]
[grid=none, frame=none]
|====
| <> \| <> \| <> >| <> \| <> \| <>
|====
endif::[]
[[tutorial]]
== Tutorial
[[tutorial_transporting_data]]
=== Transporting of Arbitrary Data to the Catch Site
All exception types that derive from `boost::<>` can be used as type-safe containers of arbitrary data objects, while complying with the no-throw requirements (15.5.1) of the ANSI {CPP} standard for exception types.
When exceptions derive from `boost::<>`, arbitrary data can be added to exception objects:
* At the point of the throw;
* At a later time as exceptions bubble up the call stack.
==== Adding of Arbitrary Data at the Point of the Throw
The following example demonstrates how errno can be stored in exception objects using Boost Exception:
[source,c++]
----
#include
#include
typedef boost::error_info my_info; //(1)
struct my_error: virtual boost::exception, virtual std::exception { }; //(2)
void
f()
{
throw my_error() << my_info(42); //(3)
}
----
[.text-right]
<> | <> | <>
First, we instantiate the `<>` template using a unique identifier -- tag_my_info, and the type of the info it identifies -- int. This provides compile-time type safety for the various values stored in exception objects.
Second, we define class my_error, which derives from `boost::<>`.
Finally, (3) illustrates how the typedef from (1) can be used with `<>` to store values in exception objects at the point of the throw.
The stored my_info value can be recovered at a later time like this:
[source,c++]
----
// ...continued
void
g()
{
try
{
f();
}
catch(
my_error & x )
{
if( int const * mi=boost::get_error_info(x) )
std::cerr << "My info: " << *mi;
}
}
----
[.text-right]
<>
The `<>` function template is instantiated with the typedef from (1), and is passed an exception object of a polymorphic type. If the exception object contains the requested value, err will point to it; otherwise a null pointer is returned.
==== Adding of Arbitrary Data to Active Exception Objects
Sometimes the throw site does not have all the information that is needed at the catch site to make sense of what went wrong. Let's say we have an exception type file_read_error, which takes a file name in its constructor. Consider the following function:
[source,c++]
----
void
file_read( FILE * f, void * buffer, size_t size )
{
if( size!=fread(buffer,1,size,f) )
throw file_read_error(????);
}
----
How can the file_read function pass a file name to the exception type constructor? All it has is a FILE handle.
Using `boost::<>` allows us to free the file_read function from the burden of storing the file name in exceptions it throws:
[source,c++]
----
#include
#include
#include
#include
struct file_read_error: virtual boost::exception { };
void
file_read( FILE * f, void * buffer, size_t size )
{
if( size!=fread(buffer,1,size,f) )
throw file_read_error() << boost::errinfo_errno(errno);
}
----
[.text-right]
<> | <>
If file_read detects a failure, it throws an exception which contains the information that is available at the time, namely the errno. Other relevant information, such as the file name, can be added in a context higher up the call stack, where it is known naturally:
[source,c++]
----
#include
#include
#include
#include
boost::shared_ptr file_open( char const * file_name, char const * mode );
void file_read( FILE * f, void * buffer, size_t size );
void
parse_file( char const * file_name )
{
boost::shared_ptr f = file_open(file_name,"rb");
assert(f);
try
{
char buf[1024];
file_read( f.get(), buf, sizeof(buf) );
}
catch(
boost::exception & e )
{
e << boost::errinfo_file_name(file_name);
throw;
}
}
----
[.text-right]
<> | <>
The above function is (almost) exception-neutral -- if an exception is emitted by any function call within the try block, parse_file does not need to do any real work, but it intercepts any `boost::<>` object, stores the file name, and re-throws using a throw-expression with no operand (15.1.6). The rationale for catching any `boost::<>` object is that the file name is relevant to any failure that occurs in parse_file, _even if the failure is unrelated to file I/O_.
==== Adding Grouped Data to Exceptions
The code snippet below demonstrates how `boost::http://www.boost.org/libs/tuple/doc/tuple_users_guide.html[tuple]` can be used to bundle the name of the function that failed, together with the reported errno so that they can be added to exception objects more conveniently together:
[source,c++]
----
#include
#include
#include
#include
#include
#include
#include
#include
typedef boost::tuple clib_failure;
struct file_open_error: virtual boost::exception { };
boost::shared_ptr
file_open( char const * name, char const * mode )
{
if( FILE * f=fopen(name,mode) )
return boost::shared_ptr(f,fclose);
else
throw file_open_error() <<
boost::errinfo_file_name(name) <<
clib_failure("fopen",errno);
}
----
[.text-right]
<> | <> | <> | <>
Note that the members of a `boost::http://www.boost.org/libs/tuple/doc/tuple_users_guide.html[tuple]` are stored separately in exception objects; they can only be retrieved individually, using `<>`.
'''
[[tutorial_enable_error_info]]
=== Integrating Boost Exception in Existing Exception Class Hierarchies
Some exception hierarchies can not be modified to make `boost::<>` a base type. In this case, the `<>` function template can be used to make exception objects derive from `boost::<>` anyway. Here is an example:
[source,c++]
----
#include
#include
typedef boost::error_info std_range_min;
typedef boost::error_info std_range_max;
typedef boost::error_info std_range_index;
template
class
my_container
{
public:
size_t size() const;
T const &
operator[]( size_t i ) const
{
if( i > size() )
throw boost::enable_error_info(std::range_error("Index out of range")) <<
std_range_min(0) <<
std_range_max(size()) <<
std_range_index(i);
//....
}
};
----
[.text-right]
<> | <>
The call to `<>` gets us an object of _unspecified type_ which is guaranteed to derive from both `boost::<>` and T. This makes it possible to use `<>` to store additional information in the exception object. The exception can be intercepted as T &, so existing exception handling will not break. It can also be intercepted as `boost::<>` &, so that <>.
'''
[[tutorial_exception_ptr]]
=== Transporting of Exceptions Between Threads
Boost Exception supports transporting of exception objects between threads through cloning. This system is similar to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html[N2179], but because Boost Exception can not rely on language support, the use of `<>` at the time of the throw is required in order to use cloning.
NOTE: All exceptions emitted by the familiar function `boost::<>` are guaranteed to derive from `boost::<>` and to support cloning.
==== Using enable_current_exception at the Time of the Throw
Here is how cloning can be enabled in a throw-expression (15.1):
[source,c++]
----
#include
#include
#include
#include
struct file_read_error: virtual boost::exception { };
void
file_read( FILE * f, void * buffer, size_t size )
{
if( size!=fread(buffer,1,size,f) )
throw boost::enable_current_exception(file_read_error()) <<
boost::errinfo_errno(errno);
}
----
[.text-right]
<> | <>
Of course, `<>` may be used with any exception type; there is no requirement that it should derive from `boost::<>`.
==== Cloning and Re-Throwing an Exception
When you catch an exception, you can call `<>` to get an `<>` object:
[source,c++]
----
#include
#include
#include
void do_work(); //throws cloning-enabled boost::exceptions
void
worker_thread( boost::exception_ptr & error )
{
try
{
do_work();
error = boost::exception_ptr();
}
catch(
... )
{
error = boost::current_exception();
}
}
----
[.text-right]
<> | <>
In the above example, note that `<>` captures the original type of the exception object. The exception can be thrown again using the `<>` function:
[source,c++]
----
// ...continued
void
work()
{
boost::exception_ptr error;
boost::thread t( boost::bind(worker_thread,boost::ref(error)) );
t.join();
if( error )
boost::rethrow_exception(error);
}
----
[.text-right]
<> | <>
Note that `<>` could fail to copy the original exception object in the following cases:
* if there is not enough memory, in which case the returned `<>` points to an instance of std::bad_alloc, or
* if `<>` was not used in the throw-expression passed to the original throw statement and the current implementation does not have the necessary compiler-specific support to copy the exception automatically, in which case the returned `<>` points to an instance of `<>`.
Regardless, the use of `<>` and `<>` in the above examples is well-formed.
'''
[[exception_types_as_simple_semantic_tags]]
=== Exception Types as Simple Semantic Tags
Deriving from `boost::<>` effectively decouples the semantics of a failure from the information that is relevant to each individual instance of reporting a failure with a given semantic.
In other words: with `boost::<>`, what data a given exception object transports depends primarily on the context in which failures are reported (not on its type.) Since exception types need no members, it becomes very natural to throw exceptions that derive from more than one type to indicate multiple appropriate semantics:
[source,c++]
----
struct exception_base: virtual std::exception, virtual boost::exception { };
struct io_error: virtual exception_base { };
struct file_error: virtual io_error { };
struct read_error: virtual io_error { };
struct file_read_error: virtual file_error, virtual read_error { };
----
[.text-right]
<>
Using this approach, exception types become a simple tagging system for categorizing errors and selecting failures in exception handlers.
'''
[[using_virtual_inheritance_in_exception_types]]
=== Using Virtual Inheritance in Exception Types
Exception types should use virtual inheritance when deriving from other exception types. This insight is due to Andrew Koenig. Using virtual inheritance prevents ambiguity problems in the exception handler:
[source,c++]
----
#include
struct my_exc1 : std::exception { char const* what() const throw(); };
struct my_exc2 : std::exception { char const* what() const throw(); };
struct your_exc3 : my_exc1, my_exc2 {};
int
main()
{
try { throw your_exc3(); }
catch(std::exception const& e) {}
catch(...) { std::cout << "whoops!" << std::endl; }
}
----
The program above outputs "whoops!" because the conversion to std::exception is ambiguous.
The overhead introduced by virtual inheritance is always negligible in the context of exception handling. Note that virtual bases are initialized directly by the constructor of the most-derived-type (the type passed to the throw statement, in case of exceptions.) However, typically this detail is of no concern when `boost::<>` is used, because it enables exception types to be trivial structs with no members (there's nothing to initialize.) See <>.
'''
[[tutorial_diagnostic_information]]
=== Diagnostic Information
Boost Exception provides a namespace-scope function `<>` which takes a `boost::<>`. The returned string contains:
* the string representation of all data objects added to the `boost::<>` through `<>`;
* the output from std::exception::what;
* additional platform-specific diagnostic information.
The returned string is not presentable as a friendly user message, but because it is generated automatically, it is useful for debugging or logging purposes. Here is an example:
[source,c++]
----
#include
#include
void f(); //throws unknown types that derive from boost::exception.
void
g()
{
try
{
f();
}
catch(
boost::exception & e )
{
std::cerr << diagnostic_information(e);
}
}
----
[.text-right]
<>
.Example:
this is a possible output from the `<>` function, as used in _libs/exception/example/example_io.cpp:_
----
example_io.cpp(70): Throw in function class boost::shared_ptr __cdecl my_fopen(const char *,const char *)
Dynamic exception type: class boost::exception_detail::clone_impl
std::exception::what: example_io error
[struct boost::errinfo_api_function_ *] = fopen
[struct boost::errinfo_errno_ *] = 2, "No such file or directory"
[struct boost::errinfo_file_name_ *] = tmp1.txt
[struct boost::errinfo_file_open_mode_ *] = rb
----
[[synopsis]]
== Synopsis
This section lists each public header file, documenting the definitions it provides.
[[synopsis-exception]]
=== `exception.hpp`
====
.#include
[source,c++]
----
namespace boost
{
class exception
{
protected:
exception();
exception( exception const & x );
~exception();
};
template
class error_info;
typedef error_info throw_function;
typedef error_info throw_file;
typedef error_info throw_line;
}
----
[.text-right]
Reference: <> | <>
====
[[synopsis-error_info]]
=== `error_info.hpp`
====
.#include
[source,c++]
----
namespace boost
{
template
class error_info;
}
----
[.text-right]
Reference: <>
====
[[synopsis-info]]
=== `info.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
template
class error_info
{
public:
typedef T value_type;
error_info( value_type const & v );
value_type const & value() const;
value_type & value();
};
template
E const & operator<<( E const & x, error_info const & v );
}
----
[.text-right]
Reference: <> | <>
====
[[synopsis-info_tuple]]
=== `info_tuple.hpp`
====
.#include
[source,c++]
----
#include
#include
namespace boost
{
template
E const & operator<<( E const & x,
tuple<
error_info,
...,
error_info > const & v );
}
----
[.text-right]
Reference: <>
====
[[synopsis-enable_error_info]]
=== `enable_error_info.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
template
---unspecified--- enable_error_info( T const & x );
}
----
[.text-right]
Reference: <>
====
[[synopsis-diagnostic_information]]
=== `diagnostic_information.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
class exception;
template
std::string diagnostic_information( E const & e, bool verbose=true );
std::string diagnostic_information( exception_ptr const & p, bool verbose=true );
char const * diagnostic_information_what( boost::exception const & e, bool verbose=true ) throw();
std::string current_exception_diagnostic_information();
}
----
[.text-right]
Reference: <> | <> | <>
====
[[synopsis-current_exception_cast]]
=== `current_exception_cast.hpp`
====
.#include
[source,c++]
----
namespace boost
{
template
E * current_exception_cast();
}
----
[.text-right]
Reference: <>
====
[[synopsis-exception_ptr]]
=== `exception_ptr.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
class unknown_exception:
public std::exception
public boost::exception
{
---unspecified---
};
typedef error_info original_exception_type;
typedef ---unspecified--- exception_ptr;
template
exception_ptr copy_exception( T const & e );
exception_ptr current_exception();
void rethrow_exception( exception_ptr const & ep );
}
----
[.text-right]
Reference: <> | <> | <> | <> | <> | <>
====
[[synopsis-enable_current_exception]]
=== `enable_current_exception.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
template
---unspecified--- enable_current_exception( T const & e );
}
----
[.text-right]
Reference: <>
====
[[synopsis-throw_exception]]
=== `throw_exception.hpp`
====
.#include
[source,c++]
----
#if !defined( BOOST_EXCEPTION_DISABLE )
#include
#include
#define BOOST_THROW_EXCEPTION(x)\
::boost::throw_exception( ::boost::enable_error_info(x) <<\
::boost::throw_file(__FILE__) <<\
::boost::throw_line((int)__LINE__) )
#else
#define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(x)
#endif
namespace boost
{
#ifdef BOOST_NO_EXCEPTIONS
void throw_exception( std::exception const & e ); // user defined
#else
template
void throw_exception( E const & e );
#endif
}
----
[.text-right]
Reference: <> | <>
====
[[synopsis-errinfo_api_function]]
=== `errinfo_api_function.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
typedef error_info errinfo_api_function;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_at_line]]
=== `errinfo_at_line.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
typedef error_info errinfo_at_line;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_errno]]
=== `errinfo_errno.hpp`
====
.#include
[source,c++]
----
#include
#include
namespace boost
{
typedef error_info errinfo_errno;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_file_handle]]
=== `errinfo_file_handle.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
template class weak_ptr;
typedef error_info > errinfo_file_handle;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_file_name]]
=== `errinfo_file_name.hpp`
====
.#include
[source,c++]
----
#include
#include
namespace boost
{
typedef error_info errinfo_file_name;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_file_open_mode]]
=== `errinfo_file_open_mode.hpp`
====
.#include
[source,c++]
----
#include
#include
namespace boost
{
typedef error_info errinfo_file_open_mode;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_nested_exception]]
=== `errinfo_nested_exception.hpp`
====
.#include
[source,c++]
----
#include
namespace boost
{
typedef ---unspecified--- exception_ptr;
typedef error_info errinfo_nested_exception;
}
----
[.text-right]
Reference: <>
====
[[synopsis-errinfo_type_info_name]]
=== `errinfo_type_info_name.hpp`
====
.#include
[source,c++]
----
#include
#include
namespace boost
{
typedef error_info errinfo_type_info_name;
}
----
[.text-right]
Reference: <>
====
[[synopsis-all]]
=== `all.hpp`
====
.#include
[source,c++]
----
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef BOOST_NO_EXCEPTIONS
#include
#include
#endif
----
This header includes all Boost Exception headers except `<>` (unless BOOST_NO_EXCEPTIONS is defined.)
====
[[reference]]
== Reference
TIP: The contents of each Reference section are organized alphabetically.
ifndef::backend-pdf[]
[grid=none, frame=none]
|====
| <> \| <> \| <> \| <>
|====
endif::[]
[[types]]
=== Types
[[exception]]
==== `exception`
.#include
[source,c++]
----
namespace boost
{
class exception
{
protected:
exception();
exception( exception const & x );
~exception();
};
}
----
Class `boost::exception` is designed to be used as a universal base for user-defined exception types.
An object of any type deriving from `boost::exception` can store data of arbitrary types, using the `<>` wrapper and `<>`.
To retrieve data from a `boost::exception` object, use the `<>` function template.
[[exception_constructors]]
===== `exception::exception`
[source,c++]
----
exception();
exception( exception const & x );
----
Effects: ::
+
--
* Default constructor: initializes an empty `boost::exception` object.
* Copy constructor: initializes a `boost::exception` object which shares with x the pointers to all currently stored data. Subsequently, data can be added to or retrieved from both exception objects interchangeably, however doing so concurrently from multiple threads is undefined behavior.
--
Throws: :: Nothing.
[[exception_destructor]]
===== `exception::~exception`
[source,c++]
----
~exception();
----
Effects: :: Releases all resources associated with the `boost::exception` object.
Throws: :: Nothing.
'''
[[error_info]]
==== `error_info`
.#include
[source,c++]
----
namespace boost
{
template
class error_info
{
public:
typedef T value_type;
error_info( value_type const & v );
value_type const & value() const;
value_type & value();
};
}
----
Requirements: :: T must have accessible copy constructor and must not be a reference (there is no requirement that T's copy constructor does not throw.)
This class template is used to associate a Tag type with a value type T. Objects of type `error_info` can be passed to `<>` to be stored in objects of type `boost::<>`.
The header `` provides a declaration of the `error_info` template, which is sufficient for the purpose of typedefing an instance for specific Tag and T, for example:
[source,c++]
----
#include
struct tag_errno;
typedef boost::error_info errno_info;
----
Or, the shorter equivalent:
[source,c++]
----
#include
typedef boost::error_info errno_info;
----
This errno_info typedef can be passed to `<>` (#include `` first) to store an int named tag_errno in exceptions of types that derive from `boost::<>`:
[source,c++]
----
throw file_read_error() << errno_info(errno);
----
It can also be passed to `<>` (#include `` first) to retrieve the tag_errno int from a `boost::<>`:
[source,c++]
----
catch( boost::exception & x )
{
if( int const * e=boost::get_error_info(x) )
....
}
----
For convenience and uniformity, Boost Exception defines the following commonly used `error_info` typedefs, ready for use with `<>`:
* <>
* <