Boost system error code

Errors originating from the operating system or other low-level application program interfaces (APIs) are typically reported via an integer representing an error code, either by returning the code directly from the function (e.g. pthread_mutex_init) or by using a side channel such as the errno pseudo-variable under POSIX or GetLastError() under Windows.

Introduction

Errors originating from the operating system or other low-level application
program interfaces (APIs) are typically reported via an integer representing
an error code, either by returning the code directly from the function (e.g.
pthread_mutex_init) or by using a side channel such as the errno
pseudo-variable under POSIX or GetLastError() under Windows.

However, these integer error values can only be interpreted when their source
is known. The value 5 under Windows means ERROR_ACCESS_DENIED when returned
by GetLastError(), but EIO when retrieved from errno. And conversely,
the same error condition «access denied» is represented by the value 5 when
returned by GetLastError() and 13 (EACCES) when retrieved from errno.

This means that in order for code to be able to handle errors from both
sources (to retrieve a text message describing the error, or to check whether
the error means «access denied»), it needs to know where the integer error
value originated. For this to be possible, the integer error value needs to
be accompanied by a piece of information identifying the source.

Boost.System provides a framework in which this is possible. Errors are
represented by a class error_code which contains both the error value and
a pointer to their source (called «category»), represented as a class derived
from error_category.

The category provides member functions such as message, which returns a text
message for a specific error value, and equivalent, which can be used to test
whether a specific error value correspond to an error condition such as «access
denied». error_code uses these category-provided functions in the
implementation of its message and operator== member functions.

Boost.System contains two predefined category classes, the generic category
(a reference to which is returned by generic_category()) and the system
category (system_category()). The generic category represents the error
values of the portable subset of errno values defined by the POSIX standard,
whereas the system category is OS dependent. Under POSIX, the system category
represents the errno values returned by the OS APIs (a superset of those in
the generic category), whereas under Windows, the system category represents
the error values returned by GetLastError().

The framework is extensible. Users can define their own categories by
deriving a class from error_category and implementing a function that
returns a reference to an instance of it. This capability is useful both for
describing library-defined error values, and for adapting existing C API
libraries that return integer error values.

For those who prefer error reporting via exceptions, Boost.System provides
a standard exception class system_error that stores an error_code.

Boost.System was standardized in C++11 as <system_error>. For a while,
the two were equivalent, but Boost.System has evolved since then and now
contains a number of extensions over its standard sibling:

  • A non-allocating overload of message;

  • Support for nonzero error codes meaning success, via the failed member
    functions;

  • Support for 64 bit category identifiers, as a solution to the problem
    that sometimes it’s not possible to ensure that only one instance of a
    category exists in the program;

  • Support for attaching source locations (file/line/function) to error codes;

  • A class result<T> that can be used to return either a value or an error
    code from a function;

  • Various other minor improvements.

boost::system::error_code can be converted to, and constructed from,
std::error_code.

Usage

All of the following code snippets assume that these lines

#include <boost/system.hpp>
namespace sys = boost::system;

are in effect.

Returning Errors from OS APIs under POSIX

Let’s suppose that we’re implementing a portable file wrapper
over the OS file APIs. Its general outline is shown below:

class file
{
private:

    int fd_;

public:

    // ...

    std::size_t read( void * buffer, std::size_t size, sys::error_code& ec );
    std::size_t write( void const * buffer, std::size_t size, sys::error_code& ec );
};

Since we’re implementing the POSIX version of file, its
data member is a POSIX file descriptor int fd_;, although other
implementations will differ.

Our read and write functions return the number of bytes transferred, and signal
errors via the output parameter ec, of type boost::system::error_code.

An implementation of file::read might look like this:

std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
{
    ssize_t r = ::read( fd_, buffer, size );

    if( r < 0 )
    {
        ec.assign( errno, sys::system_category() );
        return 0;
    }

    ec = {}; // ec.clear(); under C++03
    return r;
}

We first call the POSIX API read; if it returns an error, we store the errno
value in ec, using the system category, and return 0 as bytes transferred.
Otherwise, we clear ec to signal success, and return the result of ::read.

Note

Clearing ec on successful returns is an important step; do not omit it.

Under POSIX, the system category corresponds to POSIX errno values, which is
why we use it.

In principle, since the generic category also corresponds to errno values
under all platforms, we could have used it here; however, by convention under
POSIX, if the errno value comes from the OS (the «system»), we use the system
category for it. That’s because the system category values may be a
platform-specific superset of the generic (platform-independent) values.

The implementation of file::write is basically the same. We show it here for
completeness:

std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
{
    ssize_t r = ::write( fd_, buffer, size );

    if( r < 0 )
    {
        ec.assign( errno, sys::system_category() );
        return 0;
    }

    ec = {}; // ec.clear(); under C++03
    return r;
}

Returning Errors from OS APIs under Windows

Under Windows, our file object will store a HANDLE instead of an int:

class file
{
private:

    HANDLE fh_;

public:

    // as before
};

and the implementation of file::read will look like this:

std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
{
    DWORD r = 0;

    if( ::ReadFile( fh_, buffer, size, &r, 0 ) )
    {
        // success
        ec = {}; // ec.clear(); under C++03
    }
    else
    {
        // failure
        ec.assign( ::GetLastError(), sys::system_category() );
    }

    // In both cases, r is bytes transferred
    return r;
}

Here, the system category corresponds to the values defined in the system
header <winerror.h> and returned by GetLastError(). Since we use the
Win32 API ReadFile to implement file::read, and it returns the error
code via GetLastError(), we again store that value in ec as belonging
to the system category.

The implementation of file::write is, again, the same.

std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
{
    DWORD r = 0;

    if( ::WriteFile( fh_, buffer, size, &r, 0 ) )
    {
        ec = {}; // ec.clear(); under C++03
    }
    else
    {
        ec.assign( ::GetLastError(), sys::system_category() );
    }

    return r;
}

Returning Specific Errors under POSIX

Our implementation of file::read has a problem; it accepts std::size_t
values for size, but the behavior of ::read is unspecified when the
requested value does not fit in ssize_t. To avoid reliance on unspecified
behavior, let’s add a check for this condition and return an error:

std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
{
    if( size > SSIZE_MAX )
    {
        ec.assign( EINVAL, sys::generic_category() );
        return 0;
    }

    ssize_t r = ::read( fd_, buffer, size );

    if( r < 0 )
    {
        ec.assign( errno, sys::system_category() );
        return 0;
    }

    ec = {}; // ec.clear(); under C++03
    return r;
}

In this case, since we’re returning the fixed errno value EINVAL, which
is part of the portable subset defined by the generic category, we mark the
error value in ec as belonging to the generic category.

It’s possible to use system as well, as EINVAL is also a system category
value under POSIX; however, using the generic category for values belonging
to the portable errno subset is slightly preferrable.

Our implementation of file::write needs to undergo a similar treatment.
There, however, we’ll apply another change. When there’s no space left on
the disk, ::write returns a number of bytes written that is lower than
what we requested with size, but our function signals no error. We’ll make
it return ENOSPC in this case.

std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
{
    if( size > SSIZE_MAX )
    {
        ec.assign( EINVAL, sys::generic_category() );
        return 0;
    }

    ssize_t r = ::write( fd_, buffer, size );

    if( r < 0 )
    {
        ec.assign( errno, sys::system_category() );
        return 0;
    }

    if( r < size )
    {
        ec.assign( ENOSPC, sys::system_category() );
    }
    else
    {
        ec = {}; // ec.clear(); under C++03
    }

    return r;
}

We’ve used the system category to make it appear that the ENOSPC value
has come from the ::write API, mostly to illustrate that this is also a
possible approach. Using a generic value would have worked just as well.

Returning Specific Errors under Windows

Not much to say; the situation under Windows is exactly the same. The only
difference is that we must use the generic category for returning errno
values. The system category does not work; the integer values in the system
category are entirely different from those in the generic category.

std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
{
    DWORD r = 0;

    if( size > MAXDWORD )
    {
        ec.assign( EINVAL, sys::generic_category() );
    }
    else if( ::ReadFile( fh_, buffer, size, &r, 0 ) )
    {
        ec = {}; // ec.clear(); under C++03
    }
    else
    {
        ec.assign( ::GetLastError(), sys::system_category() );
    }

    return r;
}

std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
{
    DWORD r = 0;

    if( size > MAXDWORD )
    {
        ec.assign( EINVAL, sys::generic_category() );
    }
    else if( ::WriteFile( fh_, buffer, size, &r, 0 ) )
    {
        if( r < size )
        {
            ec.assign( ENOSPC, sys::generic_category() );
        }
        else
        {
            ec = {}; // ec.clear(); under C++03
        }
    }
    else
    {
        ec.assign( ::GetLastError(), sys::system_category() );
    }

    return r;
}

Attaching a Source Location to Error Codes

Unlike the standard <system_error>, Boost.System allows source locations
(file/line/function) to be stored in error_code, so that functions handling
the error can display or log the source code location where the error occurred.
To take advantage of this functionality, our POSIX file::read function needs
to be augmented as follows:

std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
{
    if( size > SSIZE_MAX )
    {
        static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION;
        ec.assign( EINVAL, sys::generic_category(), &loc );
        return 0;
    }

    ssize_t r = ::read( fd_, buffer, size );

    if( r < 0 )
    {
        static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION;
        ec.assign( errno, sys::system_category(), &loc );
        return 0;
    }

    ec = {}; // ec.clear(); under C++03
    return r;
}

That is, before every ec.assign statement, we need to declare a
static constexpr variable holding the current source location, then pass
a pointer to it to assign. Since error_code is small and there’s no space
in it for more than a pointer, we can’t just store the source_location in it
by value.

BOOST_CURRENT_LOCATION is a macro expanding to the current source location
(a combination of __FILE__, __LINE__, and BOOST_CURRENT_FUNCTION.)
It’s defined and documented in Boost.Assert.

Under C++03, instead of static constexpr, one needs to use static const.
Another option is BOOST_STATIC_CONSTEXPR, a
Boost.Config macro that expands to either
static constexpr or static const, as appropriate.

To avoid repeating this boilerplate each time we do ec.assign, we can define
a macro:

#define ASSIGN(ec, ...) { 
    BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; 
    (ec).assign(__VA_ARGS__, &loc); }

which we can now use to augment, for example, the POSIX implementation of file::write:

std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
{
    if( size > SSIZE_MAX )
    {
        ASSIGN( ec, EINVAL, sys::generic_category() );
        return 0;
    }

    ssize_t r = ::write( fd_, buffer, size );

    if( r < 0 )
    {
        ASSIGN( ec, errno, sys::system_category() );
        return 0;
    }

    if( r < size )
    {
        ASSIGN( ec, ENOSPC, sys::generic_category() );
    }
    else
    {
        ec = {}; // ec.clear(); under C++03
    }

    return r;
}

Obtaining Textual Representations of Error Codes for Logging and Display

Assuming that we have an error_code instance ec, returned to us by some
function, we have a variety of means to obtain textual representations of the
error code represented therein.

ec.to_string() gives us the result of streaming ec into a std::ostream,
e.g. if std::cout << ec << std::endl; outputs system:6, this is what
ec.to_string() will return. (system:6 under Windows is ERROR_INVALID_HANDLE
from <winerror.h>.)

To obtain a human-readable error message corresponding to this code, we can
use ec.message(). For ERROR_INVALID_HANDLE, it would give us «The handle is
invalid» — possibly localized.

If ec contains a source location, we can obtain its textual representation
via ec.location().to_string(). This will give us something like

C:Projectstestbed2019testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)'

if there is a location in ec, and

(unknown source location)

if there isn’t. (ec.has_location() is true when ec contains a location.)

Finally, ec.what() will give us a string that contains all of the above,
something like

The handle is invalid [system:6 at C:Projectstestbed2019testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)']

Most logging and diagnostic output that is not intended for the end user would
probably end up using what(). (ec.what(), augmented with the prefix
supplied at construction, is also what boost::system::system_error::what()
would return.)

Composing Functions Returning Error Codes

Let’s suppose that we need to implement a file copy function, with the following
interface:

std::size_t file_copy( file& src, file& dest, sys::error_code& ec );

file_copy uses src.read to read bytes from src, then writes these bytes
to dest using dest.write. This continues until one of these operations signals
an error, or until end of file is reached. It returns the number of bytes written,
and uses ec to signal an error.

Here is one possible implementation:

std::size_t file_copy( file& src, file& dest, sys::error_code& ec )
{
    std::size_t r = 0;

    for( ;; )
    {
        unsigned char buffer[ 1024 ];

        std::size_t n = src.read( buffer, sizeof( buffer ), ec );

        // read failed, leave the error in ec and return
        if( ec.failed() ) return r;

        // end of file has been reached, exit loop
        if( n == 0 ) return r;

        r += dest.write( buffer, n, ec );

        // write failed, leave the error in ec and return
        if( ec.failed() ) return r;
    }
}

Note that there is no longer any difference between POSIX and Windows
implementations; their differences are contained in file::read and
file::write. file_copy is portable and works under any platform.

The general pattern in writing such higher-level functions is that
they pass the output error_code parameter ec they received from
the caller directly as the output parameter to the lower-level functions
they are built upon. This way, when they detect a failure in an intermediate
operation (by testing ec.failed()), they can immediately return to the
caller, because the error code is already in its proper place.

Note that file_copy doesn’t even need to clear ec on success, by
using ec = {};. Since we’ve already tested ec.failed(), we know that
ec contains a value that means success.

Providing Dual (Throwing and Nonthrowing) Overloads

Functions that signal errors via an output error_code& ec parameter
require that the caller check ec after calling them, and take appropriate
action (such as return immediately, as above.) Forgetting to check ec
results in logic errors.

While this is a preferred coding style for some, others prefer exceptions,
which one cannot forget to check.

An approach that has been introduced by
Boost.Filesystem (which later turned
into std::filesystem) is to provide both alternatives: a nonthrowing
function taking error_code& ec, as file_copy above, and a throwing
function that does not take an error_code output parameter, and throws
exceptions on failure.

This is how this second throwing function is typically implemented:

std::size_t file_copy( file& src, file& dest )
{
    sys::error_code ec;
    std::size_t r = file_copy( src, dest, ec );

    if( ec.failed() ) throw sys::system_error( ec, __func__ );

    return r;
}

That is, we simply call the nonthrowing overload of file_copy, and if
it signals failure in ec, throw a system_error exception.

We use our function name __func__ ("file_copy") as the prefix,
although that’s a matter of taste.

Note that typically under this style the overloads taking error_code& ec
are decorated with noexcept, so that it’s clear that they don’t throw
exceptions (although we haven’t done so in the preceding examples in order
to keep the code C++03-friendly.)

result<T> as an Alternative to Dual APIs

Instead of providing two functions for every operation, an alternative
approach is to make the function return sys::result<T> instead of T.
result<T> is a class holding either T or error_code, similar to
variant<T, error_code>.

Clients that prefer to check for errors and not rely on exceptions can
test whether a result<T> r contains a value via if( r ) or its more
verbose equivalent if( r.has_value() ), then obtain the value via
*r or r.value(). If r doesn’t contain a value, the error_code
it holds can be obtained with r.error().

Those who prefer exceptions just call r.value() directly, without
checking. In the no-value case, this will automatically throw a
system_error corresponding to the error_code in r.

Assuming our base file API is unchanged, this variation of file_copy
would look like this:

sys::result<std::size_t> file_copy( file& src, file& dest )
{
    std::size_t r = 0;
    sys::error_code ec;

    for( ;; )
    {
        unsigned char buffer[ 1024 ];

        std::size_t n = src.read( buffer, sizeof( buffer ), ec );

        if( ec.failed() ) return ec;
        if( n == 0 ) return r;

        r += dest.write( buffer, n, ec );

        if( ec.failed() ) return ec;
    }
}

The only difference here is that we return ec on error, instead of
r.

Note, however, that we can no longer return both an error code and a
number of transferred bytes; that is, we can no longer signal partial
success
. This is often not an issue at higher levels, but lower-level
primitives such as file::read and file::write might be better off
written using the old style.

Nevertheless, to demonstrate how result returning APIs are composed,
we’ll show how file_copy would look if file::read and file::write
returned result<size_t>:

class file
{
public:

    // ...

    sys::result<std::size_t> read( void * buffer, std::size_t size );
    sys::result<std::size_t> write( void const * buffer, std::size_t size );
};

sys::result<std::size_t> file_copy( file& src, file& dest )
{
    std::size_t m = 0;

    for( ;; )
    {
        unsigned char buffer[ 1024 ];

        auto r = src.read( buffer, sizeof( buffer ) );
        if( !r ) return r;

        std::size_t n = *r;
        if( n == 0 ) return m;

        auto r2 = dest.write( buffer, n );
        if( !r2 ) return r2;

        std::size_t n2 = *r2;
        m += n2;
    }
}

Testing for Specific Error Conditions

Let’s suppose that we have called a function that signals failure
using error_code, we have passed it an error_code variable ec,
and now for some reason want to check whether the function has
failed with an error code of EINVAL, «invalid argument».

Since error_code can be compared for equality, our first instict
might be if( ec == error_code( EINVAL, generic_category() ).

This is wrong, and we should never do it.

First, under POSIX, the function might have returned EINVAL from
the system category (because the error might have been returned by
an OS API, and not by the function itself, as was the case in our
read and write implementations.)

Since error_code comparisons are exact, EINVAL from the generic
category does not compare equal to EINVAL from the system category.

(And before you start thinking about just comparing ec.value() to
EINVAL, read on.)

Second, under Windows, the function might have returned error_code(
ERROR_INVALID_PARAMETER, system_category() )
. As we have already
mentioned, the integer error values in the system category under
Windows are completely unrelated to the integer errno values.

The correct approach is to compare ec not to specific error codes,
but to error_condition( EINVAL, generic_category() ). Error
conditions are a platform-independent way to represent the meaning
of the concrete error codes. In our case, all error codes, under
both POSIX and Windows, that represent EINVAL will compare equal
to error_condition( EINVAL, generic_category() ).

In short, you should never compare error codes to error codes, and
should compare them to error conditions instead. This is the purpose
of the error_condition class, which is very frequently misunderstood.

Since

if( ec == sys::error_condition( EINVAL, sys::generic_category() ) )
{
    // handle EINVAL
}

is a bit verbose, Boost.System provides enumerator values for the
errno values against which an error code can be compared directly.

These enumerators are defined in <boost/system/errc.hpp>,
and enable the above test to be written

if( ec == sys::errc::invalid_argument )
{
    // handle EINVAL
}

which is what one should generally use for testing for a specific error
condition, as a best practice.

Adapting Existing Integer Error Values

Libraries with C (or extern "C") APIs often signal failure by returning
a library-specific integer error code (with zero typically being reserved
for «no error».) When writing portable C++ wrappers, we need to decide
how to expose these error codes, and using error_code is a good way to
do it.

Because the integer error codes are library specific, and in general match
neither errno values or system category values, we need to define a
library-specific error category.

Adapting SQLite Errors

We’ll take SQLite as an example. The general outline of a custom error
category is as follows:

class sqlite3_category_impl: public sys::error_category
{
    // TODO add whatever's needed here
};

sys::error_category const& sqlite3_category()
{
    static const sqlite3_category_impl instance;
    return instance;
}

which can then be used similarly to the predefined generic and system
categories:

int r = some_sqlite3_function( ... );
ec.assign( r, sqlite3_category() );

If we try to compile the above category definition as-is, it will complain
about our not implementing two pure virtual member functions, name and
message, so at minimum, we’ll need to add these. In addition, we’ll also
implement the non-allocating overload of message. It’s not pure virtual,
but its default implementation calls the std::string-returning overload,
and that’s almost never what one wants. (This default implementation is only
provided for backward compatibility, in order to not break existing
user-defined categories that were written before this overload was added.)

So, the minimum we need to implement is this:

class sqlite3_category_impl: public sys::error_category
{
public:

    const char * name() const noexcept;
    std::string message( int ev ) const;
    char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
};

name is easy, it just returns the category name:

const char * sqlite3_category_impl::name() const noexcept
{
    return "sqlite3";
}

message is used to obtain an error message given an integer error code.
SQLite provides the function sqlite3_errstr for this, so we don’t need
to do any work:

std::string sqlite3_category_impl::message( int ev ) const
{
    return sqlite3_errstr( ev );
}

char const * sqlite3_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
{
    std::snprintf( buffer, len, "%s", sqlite3_errstr( ev ) );
    return buffer;
}

and we’re done. sqlite3_category() can now be used like the predefined
categories, and we can put an SQLite error code int r into a Boost.System
error_code ec by means of ec.assign( r, sqlite3_category() ).

Adapting ZLib Errors

Another widely used C library is ZLib, and the portion of zlib.h that
defines its error codes is shown below:

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
 * are errors, positive values are used for special but normal events.
 */

There are three relevant differences with the previous case of SQLite:

  • While for SQLite all non-zero values were errors, as is the typical case,
    here negative values are errors, but positive values are «special but normal»,
    that is, they represent success, not failure;

  • ZLib does not provide a function that returns the error message corresponding
    to a specific error code;

  • When Z_ERRNO is returned, the error code should be retrieved from errno.

Our category implementation will look like this:

class zlib_category_impl: public sys::error_category
{
public:

    const char * name() const noexcept;

    std::string message( int ev ) const;
    char const * message( int ev, char * buffer, std::size_t len ) const noexcept;

    bool failed( int ev ) const noexcept;
};

sys::error_category const& zlib_category()
{
    static const zlib_category_impl instance;
    return instance;
}

As usual, the implementation of name is trivial:

const char * zlib_category_impl::name() const noexcept
{
    return "zlib";
}

We’ll need to work a bit harder to implement message this time, as there’s
no preexisting function to lean on:

char const * zlib_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
{
    switch( ev )
    {
    case Z_OK:            return "No error";
    case Z_STREAM_END:    return "End of stream";
    case Z_NEED_DICT:     return "A dictionary is needed";
    case Z_ERRNO:         return "OS API error";
    case Z_STREAM_ERROR:  return "Inconsistent stream state or invalid argument";
    case Z_DATA_ERROR:    return "Data error";
    case Z_MEM_ERROR:     return "Out of memory";
    case Z_BUF_ERROR:     return "Insufficient buffer space";
    case Z_VERSION_ERROR: return "Library version mismatch";
    }

    std::snprintf( buffer, len, "Unknown zlib error %d", ev );
    return buffer;
}

This is a typical implementation of the non-throwing message overload. Note
that message is allowed to return something different from buffer, which
means that we can return character literals directly, without copying them
into the supplied buffer first. This allows our function to return the correct
message text even when the buffer is too small.

The std::string overload of message is now trivial:

std::string zlib_category_impl::message( int ev ) const
{
    char buffer[ 64 ];
    return this->message( ev, buffer, sizeof( buffer ) );
}

Finally, we need to implement failed, in order to override its default
behavior of returning true for all nonzero values:

bool zlib_category_impl::failed( int ev ) const noexcept
{
    return ev < 0;
}

This completes the implementation of zlib_category() and takes care of the
first two bullets above, but we still haven’t addressed the third one; namely,
that we need to retrieve the error from errno in the Z_ERRNO case.

To do that, we’ll define a helper function that would be used to assign a ZLib
error code to an error_code:

void assign_zlib_error( sys::error_code & ec, int r )
{
    if( r != Z_ERRNO )
    {
        ec.assign( r, zlib_category() );
    }
    else
    {
        ec.assign( errno, sys::generic_category() );
    }
}

so that, instead of using ec.assign( r, zlib_category() ) directly, code
would do

int r = some_zlib_function( ... );
assign_zlib_error( ec, r );

We can stop here, as this covers everything we set out to do, but we can take
an extra step and enable source locations for our error codes. For that, we’ll
need to change assign_zlib_error to take a source_location:

void assign_zlib_error( sys::error_code & ec, int r, boost::source_location const* loc )
{
    if( r != Z_ERRNO )
    {
        ec.assign( r, zlib_category(), loc );
    }
    else
    {
        ec.assign( errno, sys::generic_category(), loc );
    }
}

Define a helper macro to avoid the boilerplate of defining the static
constexpr
source location object each time:

#define ASSIGN_ZLIB_ERROR(ec, r) { 
    BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; 
    assign_zlib_error( ec, r, &loc ); }

And then use the macro instead of the function:

int r = some_zlib_function( ... );
ASSIGN_ZLIB_ERROR( ec, r );

Supporting Comparisons against Conditions

We notice that some of the ZLib error codes correspond to portable errno
conditions. Z_STREAM_ERROR, for instance, is returned in cases where
POSIX functions would have returned EINVAL; Z_MEM_ERROR is ENOMEM;
and Z_BUF_ERROR, insufficient space in the output buffer to store the
result, roughly corresponds to ERANGE, result out of range.

To encode this relationship, we need to implement either
default_error_condition or equivalent in our category. Since we have
a simple one to one mapping, the former will suffice:

class zlib_category_impl: public sys::error_category
{
public:

    const char * name() const noexcept;

    std::string message( int ev ) const;
    char const * message( int ev, char * buffer, std::size_t len ) const noexcept;

    bool failed( int ev ) const noexcept;

    sys::error_condition default_error_condition( int ev ) const noexcept;
};

The implementation is straightforward:

sys::error_condition zlib_category_impl::default_error_condition( int ev ) const noexcept
{
    switch( ev )
    {
    case Z_OK:            return sys::error_condition();
    case Z_STREAM_ERROR:  return sys::errc::invalid_argument;
    case Z_MEM_ERROR:     return sys::errc::not_enough_memory;
    case Z_BUF_ERROR:     return sys::errc::result_out_of_range;
    }

    return sys::error_condition( ev, *this );
}

Once this is added, we will be able to compare a ZLib error_code ec against
errc enumerators:

if( ec == sys::errc::not_enough_memory )
{
    // Z_MEM_ERROR, or ENOMEM
}

Defining Library-Specific Error Codes

Let’s suppose that we are writing a library libmyimg for reading some
hypothetical image format, and that we have defined the following API
function for that:

namespace libmyimg
{

struct image;

void load_image( file& f, image& im, sys::error_code& ec );

} // namespace libmyimg

(using our portable file class from the preceding examples.)

Our hypothetical image format is simple, consisting of a fixed header,
followed by the image data, so an implementation of load_image might
have the following structure:

namespace libmyimg
{

struct image_header
{
    uint32_t signature;
    uint32_t width;
    uint32_t height;
    uint32_t bits_per_pixel;
    uint32_t channels;
};

void load_image_header( file& f, image_header& im, sys::error_code& ec );

struct image;

void load_image( file& f, image& im, sys::error_code& ec )
{
    image_header ih = {};
    load_image_header( f, ih, ec );

    if( ec.failed() ) return;

    if( ih.signature != 0xFF0AD71A )
    {
        // return an "invalid signature" error
    }

    if( ih.width == 0 )
    {
        // return an "invalid width" error
    }

    if( ih.height == 0 )
    {
        // return an "invalid height" error
    }

    if( ih.bits_per_pixel != 8 )
    {
        // return an "unsupported bit depth" error
    }

    if( ih.channels != 1 && ih.channels != 3 && ih.channels != 4 )
    {
        // return an "unsupported channel count" error
    }

    // initialize `im` and read image data

    // ...
}

} // namespace libmyimg

We can see that we need to define five error codes of our own. (Our function
can also return other kinds of failures in ec — those will come from
file::read which load_image_header will use to read the header.)

To define these errors, we’ll use a scoped enumeration type. (This example
will take advantage of C++11 features.)

namespace libmyimg
{

enum class error
{
    success = 0,

    invalid_signature,
    invalid_width,
    invalid_height,
    unsupported_bit_depth,
    unsupported_channel_count
};

} // namespace libmyimg

Boost.System supports being told that an enumeration type represents an error
code, which enables implicit conversions between the enumeration type and
error_code. It’s done by specializing the is_error_code_enum type trait,
which resides in namespace boost::system like the rest of the library:

namespace boost
{
namespace system
{

template<> struct is_error_code_enum< ::libmyimg::error >: std::true_type
{
};

} // namespace system
} // namespace boost

Once this is in place, we can now assign values of libmyimg::error to
sys::error_code, which enables the implementation of load_image to be
written as follows:

void load_image( file& f, image& im, sys::error_code& ec )
{
    image_header ih = {};
    load_image_header( f, ih, ec );

    if( ec.failed() ) return;

    if( ih.signature != 0xFF0AD71A )
    {
        ec = error::invalid_signature;
        return;
    }

    if( ih.width == 0 )
    {
        ec = error::invalid_width;
        return;
    }

    if( ih.height == 0 )
    {
        ec = error::invalid_height;
        return;
    }

    if( ih.bits_per_pixel != 8 )
    {
        ec = error::unsupported_bit_depth;
        return;
    }

    if( ih.channels != 1 && ih.channels != 3 && ih.channels != 4 )
    {
        ec = error::unsupported_channel_count;
        return;
    }

    // initialize `image` and read image data

    // ...
}

This is however not enough; we still need to define the error category
for our enumerators, and associate them with it.

The first step follows our previous two examples very closely:

namespace libmyimg
{

class myimg_category_impl: public sys::error_category
{
public:

    const char * name() const noexcept;

    std::string message( int ev ) const;
    char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
};

const char * myimg_category_impl::name() const noexcept
{
    return "libmyimg";
}

std::string myimg_category_impl::message( int ev ) const
{
    char buffer[ 64 ];
    return this->message( ev, buffer, sizeof( buffer ) );
}

char const * myimg_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
{
    switch( static_cast<error>( ev ) )
    {
    case error::success:                   return "No error";
    case error::invalid_signature:         return "Invalid image signature";
    case error::invalid_width:             return "Invalid image width";
    case error::invalid_height:            return "Invalid image height";
    case error::unsupported_bit_depth:     return "Unsupported bit depth";
    case error::unsupported_channel_count: return "Unsupported number of channels";
    }

    std::snprintf( buffer, len, "Unknown libmyimg error %d", ev );
    return buffer;
}

sys::error_category const& myimg_category()
{
    static const myimg_category_impl instance;
    return instance;
}

} // namespace libmyimg

The second step involves implementing a function make_error_code in
the namespace of our enumeration type error that takes error and
returns boost::system::error_code:

namespace libmyimg
{

sys::error_code make_error_code( error e )
{
    return sys::error_code( static_cast<int>( e ), myimg_category() );
}

} // namespace libmyimg

Now load_image will compile, and we just need to fill the rest of its
implementation with code that uses file::read to read the image data.

There’s one additional embellishment we can make. As we know, Boost.System
was proposed for, and accepted into, the C++11 standard, and now there’s
a standard implementation of it in <system_error>. We can make our
error enumeration type compatible with std::error_code as well, by
specializing the standard type trait std::is_error_code_enum:

namespace std
{

template<> struct is_error_code_enum< ::libmyimg::error >: std::true_type
{
};

} // namespace std

This makes our enumerators convertible to std::error_code.

(The reason this works is that boost::system::error_code is convertible
to std::error_code, so the return value of our make_error_code overload
can be used to initialize a std::error_code.)

Defining Library-Specific Error Conditions

All of the libmyimg::error error codes we have so far represent the same
error condition — invalid or unsupported image format. It might make sense to
enable testing for this condition without the need to enumerate all five
specific codes. To do this, we can define an error condition enumeration type:

namespace libmyimg
{

enum class condition
{
    invalid_format = 1
};

} // namespace libmyimg

which we can tag as representing an error condition by specializing
is_error_condition_enum:

namespace boost
{
namespace system
{

template<> struct is_error_condition_enum< ::libmyimg::condition >: std::true_type
{
};

} // namespace system
} // namespace boost

namespace std
{

template<> struct is_error_condition_enum< ::libmyimg::condition >: std::true_type
{
};

} // namespace std

Similarly to the error code enumeration type, which needed a make_error_code
overload, this one will need to have a make_error_condition overload, and a
category.

It’s in principle possible to reuse the category we already defined for our
error codes, by making the condition values start from, say, 10000 instead of
1. This saves some typing, but a better practice is to use a separate category
for the error conditions. So that’s what we’ll do:

namespace libmyimg
{

class myimg_condition_category_impl: public sys::error_category
{
public:

    const char * name() const noexcept;

    std::string message( int ev ) const;
    char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
};

const char * myimg_condition_category_impl::name() const noexcept
{
    return "libmyimg_condition";
}

std::string myimg_condition_category_impl::message( int ev ) const
{
    char buffer[ 64 ];
    return this->message( ev, buffer, sizeof( buffer ) );
}

char const * myimg_condition_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
{
    switch( static_cast<condition>( ev ) )
    {
    case condition::invalid_format: return "Invalid or unsupported image format";
    }

    std::snprintf( buffer, len, "Unknown libmyimg condition %d", ev );
    return buffer;
}

sys::error_category const& myimg_condition_category()
{
    static const myimg_condition_category_impl instance;
    return instance;
}

sys::error_condition make_error_condition( condition e )
{
    return sys::error_condition( static_cast<int>( e ), myimg_condition_category() );
}

} // namespace libmyimg

We have our condition, but it doesn’t do anything yet. To enable
libmyimg::condition::invalid_format to compare equal to our error codes,
we need to implement default_error_condition in the error code category:

namespace libmyimg
{

class myimg_category_impl: public sys::error_category
{
public:

    const char * name() const noexcept;

    std::string message( int ev ) const;
    char const * message( int ev, char * buffer, std::size_t len ) const noexcept;

    sys::error_condition default_error_condition( int ev ) const noexcept;
};

sys::error_condition myimg_category_impl::default_error_condition( int ev ) const noexcept
{
    switch( static_cast<error>( ev ) )
    {
    case error::success:

        return {};

    case error::invalid_signature:
    case error::invalid_width:
    case error::invalid_height:
    case error::unsupported_bit_depth:
    case error::unsupported_channel_count:

        return condition::invalid_format;
    }

    return sys::error_condition( ev, *this );
}

} // namespace libmyimg

That’s it; now ec == libmyimg::condition::invalid_format can be used to test
whether ec contains one of our error codes corresponding to the «invalid
image format» condition.

Revision History

Changes in Boost 1.81

  • The macro BOOST_SYSTEM_DISABLE_THREADS can now be defined to disable
    the use of <mutex> (e.g. on single-threaded libstdc++).

  • Added value_type, error_type, in_place_value, in_place_error
    to result<>.

  • Added emplace to result<>.

Changes in Boost 1.80

  • When an error_code is converted to std::error_code and then back
    to error_code, the original is now restored, if possible.

  • Reworked the conversion from error_category to std::error_category
    to avoid the one-time allocation that shows up on leak checkers.

  • Added a constructor that allows replacing the source location of an
    error_code, and a corresponding assign.

  • Added a converting constructor to result.

Changes in Boost 1.79

  • Added a boost::source_location parameter to throw_exception_from_error.

  • Added throw_exception_from_error overloads for errc::errc_t,
    std::error_code, std::errc, std::exception_ptr.

  • result<T>::value now automatically supplies BOOST_CURRENT_LOCATION to
    throw_exception_from_error via a default argument.

  • Added an errc::make_error_code overload taking a source location.

Changes in Boost 1.78

  • Added support for source locations to error_code.

  • Added error_code::to_string, error_condition::to_string, error_code::what.

  • system_error::what() now contains the source location, if present.

  • Added result<T, E = error_code>, a class holding either a value or an
    error, defined in <boost/system/result.hpp>.

Changes in Boost 1.77

  • The conversion operator from error_category to std::error_category
    has been improved and no longer requires <map> or <mutex>.

  • The comparison operators of error_category are now inline friends
    instead of member functions (a side effect of the previous change.)

  • error_condition now defers calling generic_category() to avoid
    instantiating the object until it’s actually needed.

  • error_condition::failed and error_condition::message have been
    undeprecated, and operator bool() now once again returns failed().

  • The system category now doesn’t call generic_category(), to avoid
    instantiating the object.

  • The return value of default_error_condition changes in some cases into
    an error_condition from the generic category, instead of from the system
    category. This happens on POSIX when the input error_code is from
    the system category and does not correspond to any errc_t value.

  • The interoperability of error_code and std::error_code has been
    improved substantially. It is now possible to construct
    boost::system::error_code from std::error_code, and it’s possible
    to pass boost::system::error_code to functions taking std::error_code&.

  • A stream insertion operator for error_condition has been added.

Changes in Boost 1.76

  • windows_error.hpp is no longer deprecated.

Changes in Boost 1.75

  • The platform-specific headers windows_error.hpp, linux_error.hpp,
    and cygwin_error.hpp emit deprecation messages and are slated for
    removal.

  • The old names for generic_category() and system_category() emit
    deprecation messages and are slated for removal.

  • error_condition::failed is deprecated and is slated for removal.
    operator bool() for error_condition has been reverted to its old
    meaning of value() != 0. This is done for compatibility with
    std::error_condition as the next release is expected to improve
    interoperability with <system_error> even further. Note that this
    does not affect
    error_code::failed, which is still alive and well.

  • The overload of error_condition::message that takes a buffer is
    deprecated and is slated for removal, for the same reasons. Note that
    this does not affect
    error_code::message.

Changes in Boost 1.74

  • operator bool() now returns failed() instead of value() != 0.

Changes in Boost 1.69

  • Boost.System is now header-only. A stub library is still built for
    compatibility, but linking to it is no longer necessary.

  • Even more functions have been marked constexpr.

  • The destructor of error_category is now protected and no longer
    virtual. This is a potentially breaking change but its impact
    is expected to be limited.

  • error_category now has a constructor that accepts a 64 bit identifier,
    enabling distinct category objects to compare equal.

  • The constructors of error_category are now protected.

  • A non-allocating, nonthrowing overload of message has been added.

  • A virtual function failed has been added, allowing categories for
    which success is not synonymous with 0.

  • The deprecated boost::system::throws object has been removed.

  • boost::throws() is now deprecated and its use is discouraged.

  • The constructor of system_error taking a single error_code argument
    is now explicit.

  • system_error::code() now returns by value.

Changes in Boost 1.68

On a C++14 compiler, many Boost.System functions and member functions
are now constexpr, and error_code and error_condition are literal
classes.

In addition to enabling use in constant expressions (and constexpr
functions), this significantly improves the quality of the generated code.

As a result of this change, however, now using Boost.System from C++14
or C++17 code requires that the library be also built with C++14 or
above. This is the default on GCC 6 and newer, but not on GCC 5 or Clang.
One can build Boost for C++14 by passing the cxxstd=14 option to b2.

(Previous versions allowed code built against any C++ standard to link
with Boost.System built against any C++ standard. In 1.68, code using
any C++ standard can link with Boost.System built with C++14 or above,
but if Boost.System is built with C++11 or below, only code also built
with C++11 and below can link to it successfully.)

Changes in Boost 1.65

On a C++11 compiler, Boost.System now provides implicit conversions
from boost::system::error_category, error_code, and error_condition
to their standard equivalents from <system_error>.

This allows libraries to expose a C++11 interface and report errors
via std::error_code even when using Boost.System, directly or through a
dependency such as Boost.ASIO.

Design Rationale

error_code and error_condition are designed as value types so
they can be copied without slicing and do not require heap allocation, but
still have polymorphic behavior based on the error category. This is achieved
by abstract base class error_category supplying the polymorphic behavior,
and error_code and error_condition containing a pointer to an object of a
type derived from error_category.

Many of the detailed design decisions were driven by the requirements that
users to be able to add additional error categories, and that it be no more
difficult to write portable code than system-specific code.

The operator<< overload for error_code eliminates a misleading conversion to
bool in code like cout << ec, where ec is of type error_code. It is also
useful in its own right.

Reference

Use of C++11 and C++14 Features

The library is documented to use several C++11 and C++14 features,
including noexcept, explicit conversion operators and constexpr. The
actual implementation uses C++11 and C++14 features only when they are
available, and otherwise falls back on C++03 features.

Macros

When BOOST_SYSTEM_ENABLE_DEPRECATED is defined, the library provides
deprecated features for compatibility. These features are bound to eventually
disappear.

When BOOST_SYSTEM_USE_UTF8 is defined, on Windows the library returns
UTF-8 messages using code page CP_UTF8 instead of the default CP_ACP.
This macro has no effect on POSIX.

When BOOST_SYSTEM_DISABLE_THREADS is defined, the library assumes that
the current platform doesn’t support multiple threads and disables the use
of the standard header <mutex>, eliminating the mutex locks. The single
threaded libstdc++ is one such platform.

Deprecated Names

In the process of adding Boost.System to the C++11 standard library, the
C++ committee changed some names. To ease transition, Boost.System deprecates
the old names, but will provide them when the macro BOOST_SYSTEM_ENABLE_DEPRECATED is defined.

Old usage, now deprecated Replacement

get_generic_category()

generic_category()

get_system_category()

system_category()

namespace posix

namespace errc

namespace posix_error

namespace errc

get_posix_category()

generic_category()

posix_category

generic_category()

errno_ecat

generic_category()

native_ecat

system_category()

<boost/system/​is_error_code_enum.hpp>

is_error_code_enum

namespace boost {
namespace system {

template<class T>
  struct is_error_code_enum { static const bool value = false; };

} // namespace system
} // namespace boost

Users may specialize is_error_code_enum for their error enumeration
types to indicate that they should be eligible for automatic conversions
to error_code. This conversion calls make_error_code(e), which should
be provided in the same namespace as the enumeration type.

<boost/system/​is_error_condition_enum.hpp>

is_error_condition_enum

namespace boost {
namespace system {

template<class T>
  struct is_error_condition_enum { static const bool value = false; };

} // namespace system
} // namespace boost

Users may specialize is_error_condition_enum for their error enumeration
types to indicate that they should be eligible for automatic conversions
to error_condition. This conversion calls make_error_condition(e), which
should be provided in the same namespace as the enumeration type.

<boost/system/​errc.hpp>

errc

namespace boost {
namespace system {

namespace errc {
  enum errc_t
  {
    success = 0,
    address_family_not_supported,   //EAFNOSUPPORT
    address_in_use,                 //EADDRINUSE
    address_not_available,          //EADDRNOTAVAIL
    already_connected,              //EISCONN
    argument_list_too_long,         //E2BIG
    argument_out_of_domain,         //EDOM
    bad_address,                    //EFAULT
    bad_file_descriptor,            //EBADF
    bad_message,                    //EBADMSG
    broken_pipe,                    //EPIPE
    connection_aborted,             //ECONNABORTED
    connection_already_in_progress, //EALREADY
    connection_refused,             //ECONNREFUSED
    connection_reset,               //ECONNRESET
    cross_device_link,              //EXDEV
    destination_address_required,   //EDESTADDRREQ
    device_or_resource_busy,        //EBUSY
    directory_not_empty,            //ENOTEMPTY
    executable_format_error,        //ENOEXEC
    file_exists,                    //EEXIST
    file_too_large,                 //EFBIG
    filename_too_long,              //ENAMETOOLONG
    function_not_supported,         //ENOSYS
    host_unreachable,               //EHOSTUNREACH
    identifier_removed,             //EIDRM
    illegal_byte_sequence,          //EILSEQ
    inappropriate_io_control_operation, //ENOTTY
    interrupted,                    //EINTR
    invalid_argument,               //EINVAL
    invalid_seek,                   //ESPIPE
    io_error,                       //EIO
    is_a_directory,                 //EISDIR
    message_size,                   //EMSGSIZE
    network_down,                   //ENETDOWN
    network_reset,                  //ENETRESET
    network_unreachable,            //ENETUNREACH
    no_buffer_space,                //ENOBUFS
    no_child_process,               //ECHILD
    no_link,                        //ENOLINK
    no_lock_available,              //ENOLCK
    no_message_available,           //ENODATA
    no_message,                     //ENOMSG
    no_protocol_option,             //ENOPROTOOPT
    no_space_on_device,             //ENOSPC
    no_stream_resources,            //ENOSR
    no_such_device_or_address,      //ENXIO
    no_such_device,                 //ENODEV
    no_such_file_or_directory,      //ENOENT
    no_such_process,                //ESRCH
    not_a_directory,                //ENOTDIR
    not_a_socket,                   //ENOTSOCK
    not_a_stream,                   //ENOSTR
    not_connected,                  //ENOTCONN
    not_enough_memory,              //ENOMEM
    not_supported,                  //ENOTSUP
    operation_canceled,             //ECANCELED
    operation_in_progress,          //EINPROGRESS
    operation_not_permitted,        //EPERM
    operation_not_supported,        //EOPNOTSUPP
    operation_would_block,          //EWOULDBLOCK
    owner_dead,                     //EOWNERDEAD
    permission_denied,              //EACCES
    protocol_error,                 //EPROTO
    protocol_not_supported,         //EPROTONOSUPPORT
    read_only_file_system,          //EROFS
    resource_deadlock_would_occur,  //EDEADLK
    resource_unavailable_try_again, //EAGAIN
    result_out_of_range,            //ERANGE
    state_not_recoverable,          //ENOTRECOVERABLE
    stream_timeout,                 //ETIME
    text_file_busy,                 //ETXTBSY
    timed_out,                      //ETIMEDOUT
    too_many_files_open_in_system,  //ENFILE
    too_many_files_open,            //EMFILE
    too_many_links,                 //EMLINK
    too_many_symbolic_link_levels,  //ELOOP
    value_too_large,                //EOVERFLOW
    wrong_protocol_type             //EPROTOTYPE
  };

} // namespace errc

template<> struct is_error_condition_enum<errc::errc_t>
  { static const bool value = true; };

constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;

constexpr error_code make_error_code( errc::errc_t e ) noexcept;

error_code make_error_code( errc::errc_t e,
  boost::source_location const * loc ) noexcept;

} // namespace system
} // namespace boost

The predefined enumeration type errc::errc_t provides named constants
corresponding to the values of the <cerrno> macros.

constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;
  • Returns:

    error_condition( e, generic_category() ).

    Since errc::errc_t provides a specialization of is_error_condition_enum
    and an overload of make_error_condition, it can be converted implicitly to
    an error_condition. This is typically useful when comparing error_code
    values returned from APIs to a portable condition, as in the below example:

  • void api_function( boost::system::error_code& ec );
    
    void my_function()
    {
        boost::system::error_code ec;
        api_function( ec );
    
        if( ec == boost::system::errc::no_such_file_or_directory )
        {
            // an entity wasn't found (ENOENT)
            // handle this condition
        }
    }
constexpr error_code make_error_code( errc::errc_t e ) noexcept;
  • Returns:

    error_code( e, generic_category() ).

    In addition to make_error_condition, errc::errc_t provides an overload of
    make_error_code. This allows the creation of generic error codes, an
    operation typically useful when a function needs to signal a generic failure
    that does not come from an underlying API, such as for instance an out of
    memory condition:

  • void my_api_function( boost::system::error_code& ec )
    {
        void* p = std::malloc( 16 );
    
        if( p == 0 )
        {
            // return ENOMEM
            ec = make_error_code( boost::system::errc::out_of_memory );
            return;
        }
    
        // use p
    }
constexpr error_code make_error_code( errc::errc_t e,
  boost::source_location const * loc ) noexcept;
  • Returns:

    error_code( e, generic_category(), loc ).

    Same as the above overload, but takes a source location.

  • void my_api_function( boost::system::error_code& ec )
    {
        void* p = std::malloc( 16 );
    
        if( p == 0 )
        {
            // return ENOMEM
    
            BOOST_STATIC_CONSTEXPR boost::source_location loc =
              BOOST_CURRENT_LOCATION;
    
            ec = make_error_code( boost::system::errc::out_of_memory, &loc );
            return;
        }
    
        // use p
    }

<boost/system/​error_category.hpp>

error_category

The class error_category defines the base class for types used
to identify the source and encoding of a particular category of error code.

Classes may be derived from error_category to support categories of
errors in addition to those defined in Boost.System.

namespace boost {
namespace system {

class error_category
{
public: // noncopyable

    error_category( error_category const & ) = delete;
    error_category& operator=( error_category const & ) = delete;

protected:

    ~error_category() = default;

    constexpr error_category() noexcept;
    explicit constexpr error_category( unsigned long long id ) noexcept;

public:

    virtual const char * name() const noexcept = 0;

    virtual error_condition default_error_condition( int ev ) const noexcept;

    virtual bool equivalent( int code, const error_condition & condition )
      const noexcept;
    virtual bool equivalent( const error_code & code, int condition )
      const noexcept;

    virtual std::string message( int ev ) const = 0;
    virtual char const * message( int ev, char * buffer, std::size_t len )
      const noexcept;

    virtual bool failed( int ev ) const noexcept;

    friend constexpr bool operator==( const error_category & lhs,
      const error_category & rhs ) noexcept;
    friend constexpr bool operator!=( const error_category & lhs,
      const error_category & rhs ) noexcept;

    friend constexpr bool operator< ( const error_category & lhs,
      const error_category & rhs ) noexcept;

    operator std::error_category const & () const;

private:

    unsigned long long id_; // exposition only
};

} // namespace system
} // namespace boost
Constructors
constexpr error_category() noexcept;
  • Effects:

    Initializes id_ to 0.

    Remarks:

    Since equivalence for categories that do not have an identifier is
    based on comparing object addresses, a user-defined derived category of type
    C that uses this constructor should ensure that only one object of type C
    exists in the program.

explicit constexpr error_category( unsigned long long id ) noexcept;
  • Effects:

    Initializes id_ to id.

    Remarks:

    User-defined derived categories that use this constructor are considered
    equivalent when their identifiers match. Therefore, those categories may have more
    than one instance existing in a program, but to minimize the possibility of
    collision, their identifiers must be randomly chosen (at the time the category
    is implemented, not at runtime). One way of generating a 64 bit random identifier
    is https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h.

Virtuals
virtual const char * name() const noexcept = 0;
  • Returns:

    In derived classes, a character literal naming the error category.

virtual error_condition default_error_condition( int ev ) const noexcept;
  • Returns:
    • In derived classes, an error condition corresponding to ev.
      The returned error condition will typically come from the generic category.

    • In the default implementation, error_condition( ev, *this ).

virtual bool equivalent( int code, const error_condition & condition )
  const noexcept;
  • Returns:
    • In derived classes, true when error_code( code, *this ) is equivalent to condition.

    • In the default implementation, default_error_condition( code ) == condition.

virtual bool equivalent( const error_code & code, int condition )
  const noexcept;
  • Returns:
    • In derived classes, true when code is equivalent to error_condition( condition, *this ).

    • In the default implementation, *this == code.category() && code.value() == condition.

virtual std::string message( int ev ) const = 0;
  • Returns:

    In derived classes, a string that describes the error denoted by ev.

virtual char const * message( int ev, char * buffer, std::size_t len )
  const noexcept;
  • Effects:
    • Derived classes should either

      • return a pointer to a character literal describing the error denoted by ev, or

      • copy a string describing the error into buffer, truncating it to len-1
        characters and storing a null terminator, and return buffer. If len is 0,
        nothing is copied, but the function still returns buffer. Note that
        when len is 0, buffer may be nullptr.

    • The default implementation calls message(ev) and copies the result into
      buffer, truncating it to len-1 characters and storing a null terminator.
      If len is 0, copies nothing. Returns buffer. If message(ev) throws an
      exception, the string "Message text unavailable" is used.

    Example:
    const char* my_category::message(int ev, char* buffer, size_t len) const noexcept
    {
        switch(ev)
        {
        case 0: return "no error";
        case 1: return "voltage out of range";
        case 2: return "impedance mismatch";
    
        case 31:
        case 32:
        case 33:
    
            std::snprintf(buffer, len, "component %d failure", ev-30);
            return buffer;
    
        default:
    
            std::snprintf(buffer, len, "unknown error %d", ev);
            return buffer;
        }
    }
virtual bool failed( int ev ) const noexcept;
  • Returns:
    • In derived classes, true when ev represents a failure.

    • In the default implementation, ev != 0.

    Remarks:

    All calls to this function with the same ev must return the same value.

Comparisons
friend constexpr bool operator==( const error_category & lhs,
  const error_category & rhs ) noexcept;
  • Returns:

    rhs.id_ == 0? &lhs == &rhs: lhs.id_ == rhs.id_.

    Remarks:

    Two category objects are considered equivalent when they have
    matching nonzero identifiers, or are the same object.

friend constexpr bool operator!=( const error_category & lhs,
  const error_category & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

constexpr bool operator< ( const error_category & lhs,
  const error_category & rhs ) const noexcept;
  • Returns:
    • If lhs.id_ < rhs.id_, true;

    • Otherwise, if lhs.id_ > rhs.id_, false;

    • Otherwise, if rhs.id_ != 0, false;

    • Otherwise, std::less<error_category const *>()( &lhs, &rhs ).

Conversions
operator std::error_category const & () const;
  • Returns:

    A reference to an std::error_category object corresponding
    to *this.

<boost/system/​system_category.hpp>

system_category

namespace boost {
namespace system {

constexpr const error_category & system_category() noexcept;

} // namespace system
} // namespace boost
constexpr const error_category & system_category() noexcept;
  • Returns:

    A reference to a predefined error_category object identifying
    errors originating from the operating system.

<boost/system/​generic_category.hpp>

generic_category

namespace boost {
namespace system {

constexpr const error_category & generic_category() noexcept;

} // namespace system
} // namespace boost
constexpr const error_category & generic_category() noexcept;
  • Returns:

    A reference to a predefined error_category object identifying
    portable error codes and conditions.

<boost/system/​error_code.hpp>

error_code

The class error_code describes an object used to hold error code
values, such as those originating from the operating system or other
low-level application program interfaces. It’s an adjunct to error reporting
by exception.

namespace boost {
namespace system {

class error_code {
public:

    // constructors

    constexpr error_code() noexcept;
    constexpr error_code( int val, const error_category & cat ) noexcept;

    error_code( int val, const error_category & cat,
      boost::source_location const * loc ) noexcept;

    template<class ErrorCodeEnum>
      constexpr error_code( ErrorCodeEnum e ) noexcept;

    error_code( error_code const& ec,
      boost::source_location const * loc ) noexcept;

    error_code( std::error_code const& ec ) noexcept;

    // modifiers

    constexpr void assign( int val, const error_category & cat ) noexcept;

    void assign( int val, const error_category & cat,
      boost::source_location const * loc ) noexcept;

    template<class ErrorCodeEnum>
      constexpr error_code & operator=( ErrorCodeEnum e ) noexcept;

    void assign( error_code const& ec,
      boost::source_location const * loc ) noexcept;

    constexpr void clear() noexcept;

    // observers

    constexpr int value() const noexcept;
    constexpr const error_category & category() const noexcept;

    error_condition default_error_condition() const noexcept;

    std::string message() const;
    char const * message( char * buffer, std::size_t len ) const noexcept;

    constexpr bool failed() const noexcept;
    constexpr explicit operator bool() const noexcept;

    bool has_location() const noexcept;
    boost::source_location const & location() const noexcept;

    // comparisons

    friend constexpr bool operator==( const error_code & lhs,
      const error_code & rhs ) noexcept;

    friend constexpr bool operator!=( const error_code & lhs,
      const error_code & rhs ) noexcept;

    friend constexpr bool operator<( const error_code & lhs,
      const error_code & rhs ) noexcept;

    friend bool operator==( const error_code & code,
      const error_condition & condition ) noexcept;
    friend bool operator==( const error_condition & condition,
      const error_code & code ) noexcept;

    friend bool operator!=( const error_code & code,
      const error_condition & condition ) noexcept;
    friend bool operator!=( const error_condition & condition,
      const error_code & code ) noexcept;

    friend bool operator==( const error_code & lhs,
      const std::error_code & rhs ) noexcept;
    friend bool operator==( const std::error_code & lhs,
      const error_code & rhs ) noexcept;

    friend bool operator!=( const error_code & lhs,
      const std::error_code & rhs ) noexcept;
    friend bool operator!=( const std::error_code & lhs,
      const error_code & rhs ) noexcept;

    template<class E>
      friend constexpr bool operator==( const error_code & lhs, E rhs ) noexcept;
    template<class E>
      friend constexpr bool operator==( E lhs, const error_code & rhs ) noexcept;

    template<class E>
      friend constexpr bool operator!=( const error_code & lhs, E rhs ) noexcept;
    template<class E>
      friend constexpr bool operator!=( E lhs, const error_code & rhs ) noexcept;

    // conversions

    operator std::error_code() const;
    operator std::error_code();
    template<class T> operator T& (); // only when T=std::error_code

    // to_string

    std::string to_string() const;

    // stream insertion

    template<class charT, class traits>
      friend std::basic_ostream<charT, traits>&
        operator<<( basic_ostream<charT, traits>& os, const error_code & ec );

    // what

    std::string what() const;
};

// non-member functions

std::size_t hash_value( const error_code & ec );

} // namespace system
} // namespace boost
Constructors
constexpr error_code() noexcept;
  • Ensures:

    value() == 0; category() == system_category(); !has_location().

constexpr error_code( int val, const error_category & cat ) noexcept;
  • Ensures:

    value() == val; category() == cat; !has_location().

error_code( int val, const error_category & cat,
  boost::source_location const * loc ) noexcept;
  • Requires:

    loc points to a valid boost::source_location object with static storage duration.

    Ensures:

    value() == val; category() == cat; has_location(); &location() == loc.

template<class ErrorCodeEnum>
  constexpr error_code( ErrorCodeEnum e ) noexcept;
  • Ensures:

    *this == make_error_code( e ).

    Remarks:

    This constructor is only enabled when is_error_code_enum<ErrorCodeEnum>::value is true.

error_code( error_code const& ec,
  boost::source_location const * loc ) noexcept;
  • Requires:

    loc points to a valid boost::source_location object with static storage duration, or is nullptr.

    Ensures:

    *this == ec.

    Remarks:

    When ec is a default-constructed error_code or wraps a std::error_code,
    or when loc is nullptr, *this stores no location (has_location() is false).
    Otherwise, *this stores loc (has_location() is true and &location() is loc.)

error_code( std::error_code const & ec ) noexcept;
  • Effects:

    Construct an error_code that wraps ec.

    Remarks:

    value() and category() are unspecified. has_location() is false.

Modifiers
constexpr void assign( int val, const error_category & cat ) noexcept;
  • Effects:

    *this = error_code( val, cat ).

void assign( int val, const error_category & cat,
  boost::source_location const * loc ) noexcept;
  • Effects:

    *this = error_code( val, cat, loc ).

template<class ErrorCodeEnum>
  constexpr error_code & operator=( ErrorCodeEnum e ) noexcept;
  • Ensures:

    *this == make_error_code( e ).

    Remarks:

    This operator is only enabled when is_error_code_enum<ErrorCodeEnum>::value is true.

void assign( error_code const& ec,
  boost::source_location const * loc ) noexcept;
  • Effects:

    *this = error_code( ec, loc ).

constexpr void clear() noexcept;
  • Effects:

    *this = error_code().

Observers
constexpr int value() const noexcept;
  • Returns:

    the error value.

constexpr const error_category & category() const noexcept;
  • Returns:

    the error category.

error_condition default_error_condition() const noexcept;
  • Returns:

    category().default_error_condition( value() ).

std::string message() const;
  • Returns:

    If *this wraps a std::error_code object ec, ec.message().
    Otherwise, category().message( value() ).

char const * message( char * buffer, std::size_t len ) const noexcept;
  • Effects:

    If *this wraps a std::error_code object ec, copies the
    string returned from ec.message() into buffer and returns buffer.
    Otherwise, returns category().message( value(), buffer, len ).

constexpr bool failed() const noexcept;
  • Returns:

    If *this wraps a std::error_code object ec, ec.value() != 0.
    Otherwise, category().failed( value() ).

constexpr explicit operator bool() const noexcept;
bool has_location() const noexcept;
  • Returns:

    true if *this has been constructed with a pointer to a source
    location, false otherwise.

boost::source_location const & location() const noexcept;
  • Returns:

    *loc if *this has been constructed with a pointer to a source
    location loc, a reference to a default-constructed boost::source_location otherwise.

Comparisons
friend constexpr bool operator==( const error_code & lhs,
  const error_code & rhs ) noexcept;
  • Returns:

    If both lhs and rhs wrap std::error_code objects e1 and e2, e1 == e2.
    Otherwise, lhs.value() == rhs.value() && lhs.category() == rhs.category().

friend constexpr bool operator!=( const error_code & lhs,
  const error_code & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

friend constexpr bool operator<( const error_code & lhs,
  const error_code & rhs ) noexcept;
  • Returns:

    If both lhs and rhs wrap std::error_code objects e1 and e2, e1 < e2.
    Otherwise, lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value()).

friend bool operator==( const error_code & code,
  const error_condition & condition ) noexcept;
friend bool operator==( const error_condition & condition,
  const error_code & code ) noexcept;
  • Returns:

    If code wraps a std::error_code object ec, ec == static_cast<std::error_condition>( condition ).
    Otherwise, code.category().equivalent( code.value(), condition ) || condition.category().equivalent( code, condition.value() ).

friend bool operator!=( const error_code & lhs,
  const error_condition & rhs ) noexcept;
friend bool operator!=( const error_condition & lhs,
  const error_code & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

friend bool operator==( const error_code & lhs,
  const std::error_code & rhs ) noexcept;
  • Returns:

    static_cast<std::error_code>(lhs) == rhs.

friend bool operator==( const std::error_code & lhs,
  const error_code & rhs ) noexcept;
  • Returns:

    lhs == static_cast<std::error_code>(rhs).

friend bool operator!=( const error_code & lhs,
  const std::error_code & rhs ) noexcept;
friend bool operator!=( const std::error_code & lhs,
  const error_code & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

template<class E>
  friend constexpr bool operator==( const error_code & lhs, E rhs ) noexcept;
    • When is_error_code_enum<E>::value is true, returns lhs == make_error_code(rhs);

    • When is_error_condition_enum<E>::value is true, returns lhs == make_error_condition(rhs);

    • Otherwise, this overload is disabled.

template<class E>
  friend constexpr bool operator==( E lhs, const error_code & rhs ) noexcept;
    • When is_error_code_enum<E>::value is true, returns make_error_code(lhs) == rhs;

    • When is_error_condition_enum<E>::value is true, returns make_error_condition(lhs) == rhs;

    • Otherwise, this overload is disabled.

template<class E>
  friend constexpr bool operator!=( const error_code & lhs, E rhs ) noexcept;
template<class E>
  friend constexpr bool operator!=( E lhs, const error_code & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

    Remarks:

    These overloads are only enabled when
    is_error_code_enum<E>::value is true or
    is_error_condition_enum<E>::value is true.

Conversions
operator std::error_code() const;
operator std::error_code();
  • Returns:

    If *this wraps a std::error_code object ec, ec.
    Otherwise, std::error_code( value(), category() ).

template<class T> operator T&();
  • Effects:

    If *this wraps a std::error_code object ec,
    returns a reference to ec.
    Otherwise, makes *this wrap std::error_code( *this ),
    then returns a reference to it.

    Remarks:

    This operator is only enabled when T is std::error_code.

to_string
std::string to_string() const;
  • Returns:

    If *this wraps a std::error_code object e2, a string that
    is the concatenation of "std:", e2.category().name(), ':', and the
    string representation of e2.value(). Otherwise, the concatenation of
    category().name(), ':', and the string representation of value().

Stream Insertion
template <class charT, class traits>
  std::basic_ostream<charT, traits>&
    operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
  • Effects:

    os << to_string().

    Returns:

    os.

what
std::string what() const;
  • Returns:

    A string representation of *this, suitable for logging and
    diagnostic output. Typically incorporates message(), to_string(), and
    location().to_string() (if available.)

Nonmembers
std::size_t hash_value( const error_code & ec );
  • Returns:

    If ec wraps a std::error_code object e2, std::hash<std::error_code>()(e2).
    Otherwise, a hash value representing ec.

<boost/system/​error_condition.hpp>

error_condition

namespace boost {
namespace system {

class error_condition {
public:

    // constructors

    constexpr error_condition() noexcept;
    constexpr error_condition( int val, const error_category & cat ) noexcept;

    template <class ErrorConditionEnum>
      constexpr error_condition( ErrorConditionEnum e ) noexcept;

    // modifiers

    constexpr void assign( int val, const error_category & cat ) noexcept;

    template<typename ErrorConditionEnum>
      constexpr error_condition & operator=( ErrorConditionEnum e ) noexcept;

    constexpr void clear() noexcept;

    // observers

    constexpr int value() const noexcept;
    constexpr const error_category & category() const noexcept;

    std::string message() const;
    char const * message( char * buffer, std::size_t len ) const noexcept;

    constexpr bool failed() const noexcept;
    constexpr explicit operator bool() const noexcept;

    // comparisons

    friend constexpr bool operator==( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

    friend constexpr bool operator!=( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

    friend constexpr bool operator<( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

    friend bool operator==( const std::error_code & code,
      const error_condition & condition ) noexcept;
    friend bool operator==( const error_condition & condition,
      const std::error_code & code ) noexcept;

    friend bool operator!=( const std::error_code & code,
      const error_condition & condition ) noexcept;
    friend bool operator!=( const error_condition & condition,
      const std::error_code & code ) noexcept;

    // conversions

    operator std::error_condition() const;

    // to_string

    std::string to_string() const;

    // stream insertion

    template <class charT, class traits>
      friend std::basic_ostream<charT, traits>&
        operator<<( basic_ostream<charT, traits>& os, const error_condition & en );
};

} // namespace system
} // namespace boost
Constructors
constexpr error_condition() noexcept;
  • Ensures:

    value() == 0; category() == generic_category().

constexpr error_condition( int val, const error_category & cat ) noexcept;
  • Ensures:

    value() == val; category() == cat.

template <class ErrorConditionEnum>
  constexpr error_condition( ErrorConditionEnum e ) noexcept;
  • Ensures:

    *this == make_error_condition( e ).

    Remarks:

    This constructor is only enabled when is_error_condition_enum<ErrorConditionEnum>::value is true.

Modifiers
constexpr void assign( int val, const error_category & cat ) noexcept;
  • Ensures:

    value() == val; category() == cat.

template <class ErrorConditionEnum>
  constexpr error_condition & operator=( ErrorConditionEnum e ) noexcept;
  • Ensures:

    *this == make_error_condition( e ).

    Remarks:

    This operator is only enabled when is_error_condition_enum<ErrorConditionEnum>::value is true.

constexpr void clear() noexcept;
  • Ensures:

    value() == 0; category() == generic_category().

Observers
constexpr int value() const noexcept;
  • Returns:

    the error value.

constexpr const error_category & category() const noexcept;
  • Returns:

    the error category.

std::string message() const;
  • Returns:

    category().message( value() ).

char const * message( char * buffer, std::size_t len ) const noexcept;
  • Returns:

    category().message( value(), buffer, len ).

constexpr bool failed() const noexcept;
  • Returns:

    category().failed( value() ).

constexpr explicit operator bool() const noexcept;
Comparisons
friend constexpr bool operator==( const error_condition & lhs,
  const error_condition & rhs ) noexcept;
  • Returns:

    lhs.value() == rhs.value() && lhs.category() == rhs.category().

friend constexpr bool operator!=( const error_condition & lhs,
  const error_condition & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

friend constexpr bool operator<( const error_condition & lhs,
  const error_condition & rhs ) noexcept;
  • Returns:

    lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value()).

friend bool operator==( const std::error_code & code,
  const error_condition & condition ) noexcept;
friend bool operator==( const error_condition & condition,
  const std::error_code & code ) noexcept;
  • Returns:

    code == static_cast<std::error_condition>( rhs ).

friend constexpr bool operator!=( const std::error_code & lhs,
  const error_condition & rhs ) noexcept;
friend constexpr bool operator!=( const error_condition & lhs,
  const std::error_code & rhs ) noexcept;
  • Returns:

    !( lhs == rhs ).

Conversions
operator std::error_condition() const;
  • Returns:

    std::error_condition( value(), category() ).

to_string
std::string to_string() const;
  • Returns:

    The concatenation of "cond:", category().name(), ':',
    and the string representation of value().

Stream Insertion
template <class charT, class traits>
  std::basic_ostream<charT, traits>&
    operator<<( basic_ostream<charT, traits>& os, const error_condition & en );
  • Effects:

    os << en.to_string().

    Returns:

    os.

<boost/system/​system_error.hpp>

system_error

The class system_error describes an exception object used to
report errors that have an associated error_code. Such errors
typically originate from operating system or other low-level
application program interfaces.

namespace boost {
namespace system {

class system_error: public std::runtime_error
{
public:

    explicit system_error( error_code ec );
    system_error( error_code ec, const char * what_arg );
    system_error( error_code ec, const std::string & what_arg );

    system_error( int ev, const error_category & ecat );
    system_error( int ev, const error_category & ecat,
      const char * what_arg );
    system_error( int ev, const error_category & ecat,
      const std::string & what_arg );

    error_code code() const noexcept;
    const char * what() const noexcept;
};

} // namespace system
} // namespace boost
Constructors
explicit system_error( error_code ec );
system_error( error_code ec, const char * what_arg );
system_error( error_code ec, const std::string & what_arg );
system_error( int ev, const error_category & ecat,
  const char * what_arg );
system_error( int ev, const error_category & ecat,
  const std::string & what_arg );
system_error( int ev, const error_category & ecat );
  • Ensures:

    code() == error_code( ev, ecat ).

Observers
error_code code() const noexcept;
  • Returns:

    ec or error_code( ev, ecat ), from the constructor, as appropriate.

const char * what() const noexcept;
  • Returns:

    A null-terminated character string incorporating the arguments supplied
    in the constructor, typically of the form what_arg + ": " + code().message().

<boost/system/result.hpp>

This header defines the class template result<T, E>. Unlike the rest of the library,
it requires C++11.

Synopsis

namespace boost {
namespace system {

// throw_exception_from_error

BOOST_NORETURN inline void throw_exception_from_error( error_code const & e,
  boost::source_location const & loc );

BOOST_NORETURN inline void throw_exception_from_error( std::error_code const & e,
  boost::source_location const & loc );

BOOST_NORETURN inline void throw_exception_from_error( errc::errc_t const & e,
  boost::source_location const & loc );

BOOST_NORETURN inline void throw_exception_from_error( std::errc const & e,
  boost::source_location const & loc );

BOOST_NORETURN inline void throw_exception_from_error( std::exception_ptr & e,
  boost::source_location const & loc );

// in_place_*

using in_place_value_t = /*unspecified*/;
constexpr in_place_value_t in_place_value{};

using in_place_error_t = /*unspecified*/;
constexpr in_place_error_t in_place_error{};

// result

template<class T, class E = error_code> class result;
template<class E> class result<void, E>;

} // namespace system
} // namespace boost

throw_exception_from_error

The function throw_exception_from_error is called by result<T, E>::value() when
the result holds an error. Its purpose is to throw an exception that represents the
error held in the result.

An implementation for the common and default case where E is error_code is
already provided. It throws system_error(e).

If result<T, E> is used with other error types, the user is expected to provide
an appropriate overload of throw_exception_from_error in the namespace of E.

BOOST_NORETURN inline void throw_exception_from_error( error_code const & e,
  boost::source_location const & loc );
  • Effects:

    boost::throw_with_location( system_error( e ), loc ).

BOOST_NORETURN inline void throw_exception_from_error( std::error_code const & e,
  boost::source_location const & loc );
  • Effects:

    boost::throw_with_location( std::system_error( e ), loc ).

BOOST_NORETURN inline void throw_exception_from_error( errc::errc_t const & e,
  boost::source_location const & loc );
  • Effects:

    boost::throw_with_location( system_error( make_error_code( e ) ), loc ).

BOOST_NORETURN inline void throw_exception_from_error( std::errc const & e,
  boost::source_location const & loc );
  • Effects:

    boost::throw_with_location( std::system_error( make_error_code( e ) ), loc ).

BOOST_NORETURN inline void throw_exception_from_error( std::exception_ptr & e,
  boost::source_location const & loc );
  • Effects:
    • If e isn’t null, std::rethrow_exception( e ).

    • Otherwise, boost::throw_with_location( std::bad_exception(), loc ).

result<T, E>

result<T, E> stores either a value of type T, or an error of type E. E defaults
to error_code. In a typical use, functions that can fail return result<T>.

namespace boost {
namespace system {

template<class T, class E = error_code> class result
{
public:

    using value_type = T;
    using error_type = E;

    static constexpr in_place_value_t in_place_value{};
    static constexpr in_place_error_t in_place_error{};

    // constructors

    constexpr result();

    template<class... A>
      constexpr result( A&&... a );

    template<class... A>
      constexpr result( in_place_value_t, A&&... a );

    template<class... A>
      constexpr result( in_place_error_t, A&&... a );

    template<class T2, class E2>
      constexpr result( result<T2, E2> const& r2 );

    template<class T2, class E2>
      constexpr result( result<T2, E2>&& r2 );

    // queries

    constexpr bool has_value() const noexcept;
    constexpr bool has_error() const noexcept;
    constexpr explicit operator bool() const noexcept;

    // checked value access

    constexpr T& value( boost::source_location const & loc =
      BOOST_CURRENT_LOCATION ) & ;

    constexpr T const& value( boost::source_location const & loc =
      BOOST_CURRENT_LOCATION ) const& ;

    constexpr T&& value( boost::source_location const & loc =
      BOOST_CURRENT_LOCATION ) && ;

    constexpr T const&& value( boost::source_location const & loc =
      BOOST_CURRENT_LOCATION ) const&& ;

    // unchecked value access

    constexpr T* operator->() noexcept;
    constexpr T const* operator->() const noexcept;

    constexpr T& operator*() & noexcept;
    constexpr T const& operator*() const & noexcept;
    constexpr T&& operator*() && noexcept;
    constexpr T const&& operator*() const && noexcept;

    // error access

    constexpr E error() const;

    // emplace

    template<class... A>
      constexpr T& emplace( A&&... a );

    // swap

    constexpr void swap( result& r );
    friend constexpr void swap( result & r1, result & r2 );

    // equality

    friend constexpr bool operator==( result const & r1, result const & r2 );
    friend constexpr bool operator!=( result const & r1, result const & r2 );
};

// stream insertion

template<class Ch, class Tr, class T, class E>
  std::basic_ostream<Ch, Tr>&
    operator<<( std::basic_ostream<Ch, Tr>& os, result<T, E> const & r );

} // namespace system
} // namespace boost
Constructors
  • Ensures:

    *this holds the value T().

    Remarks:

    This constructor is only enabled when std::is_default_constructible<T>::value is true.

template<class... A>
  constexpr result( A&&... a );
  • Effects:
    • If std::is_constructible<T, A…​>::value && !std::is_constructible<E, A…​>::value,
      ensures that *this holds the value T( std::forward<A>(a)…​ ).

    • If std::is_constructible<E, A…​>::value && !std::is_constructible<T, A…​>::value,
      ensures that *this holds the error E( std::forward<A>(a)…​ ).

    • Otherwise, this constructor does not participate in overload resolution.

    Remarks:

    This constructor is only enabled when sizeof…​(T) > 0.

template<class... A>
  constexpr result( in_place_value_t, A&&... a );
  • Ensures:

    *this holds the value T( std::forward<A>(a)…​ ).

    Remarks:

    This constructor is only enabled when std::is_constructible<T, A…​>::value is true.

template<class... A>
  constexpr result( in_place_error_t, A&&... a );
  • Ensures:

    *this holds the error E( std::forward<A>(a)…​ ).

    Remarks:

    This constructor is only enabled when std::is_constructible<E, A…​>::value is true.

template<class T2, class E2>
  constexpr result( result<T2, E2> const& r2 );
  • Ensures:

    If r2.has_value() is true, *this holds the value T( *r2 ), otherwise *this holds the value E( r2.error() ).

    Remarks:

    This constructor is only enabled when std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::value is true.

template<class T2, class E2>
  constexpr result( result<T2, E2>&& r2 );
  • Ensures:

    If r2.has_value() is true, *this holds the value T( std::move( *r2 ) ), otherwise *this holds the value E( r2.error() ).

    Remarks:

    This constructor is only enabled when std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::value is true.

Queries
constexpr bool has_value() const noexcept;
  • Returns:

    true when *this holds a value, false otherwise.

constexpr bool has_error() const noexcept;
constexpr explicit operator bool() const noexcept;
Checked Value Access
constexpr T& value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) & ;

constexpr T const& value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const& ;

constexpr T&& value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) && ;

constexpr T const&& value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const&& ;
  • Effects:

    If *this holds a value, returns a reference to it. Otherwise,
    calls throw_exception_from_error, passing it a reference to
    the held error, and loc.

Unchecked Value Access
constexpr T* operator->() noexcept;
constexpr T const* operator->() const noexcept;
  • Returns:

    If *this holds a value, a pointer to it. Otherwise, nullptr.

constexpr T& operator*() & noexcept;
constexpr T const& operator*() const & noexcept;
  • Requires:

    *this holds a value.

    Returns:

    *operator->().

constexpr T&& operator*() && noexcept;
constexpr T const&& operator*() const && noexcept;
  • Requires:

    *this holds a value.

    Returns:

    std::move( *operator->() ).

Error Access
constexpr E error() const;
  • Effects:

    If *this holds an error, returns it. Otherwise, returns E().

emplace
template<class... A>
  constexpr T& emplace( A&&... a );
  • Ensures:

    *this holds the value T( std::forward<A>(a)…​ ).

    Returns:

    A reference to the contained value.

swap
constexpr void swap( result& r );
  • Effects:

    Exchanges the contents of *this and r.

friend constexpr void swap( result & r1, result & r2 );
  • Effects:

    Exchanges the contents of r1 and r2.

Equality
friend constexpr bool operator==( result const & r1, result const & r2 );
  • Effects:
    • If r1 holds a value t1 and r2 holds a value t2, returns t1 == t2.

    • If r1 holds an error e1 and r2 holds an error e2, returns e1 == e2.

    • Otherwise, returns false.

friend constexpr bool operator!=( result const & r1, result const & r2 );
Stream Insertion
template<class Ch, class Tr, class T, class E>
  std::basic_ostream<Ch, Tr>&
    operator<<( std::basic_ostream<Ch, Tr>& os, result<T, E> const & r );
  • Effects:
    • If *this holds a value t, os << "value:" << t.

    • If *this holds an error e, os << "error:" << e.

    Returns:

    os.

result<void, E>

namespace boost {
namespace system {

template<class E> class result<void, E>
{
public:

    using value_type = void;
    using error_type = E;

    static constexpr in_place_value_t in_place_value{};
    static constexpr in_place_error_t in_place_error{};

    // constructors

    constexpr result() noexcept;

    template<class... A>
      constexpr result( A&&... a );

    constexpr result( in_place_value_t ) noexcept;

    template<class... A>
      constexpr result( in_place_error_t, A&&... a );

    // queries

    constexpr bool has_value() const noexcept;
    constexpr bool has_error() const noexcept;
    constexpr explicit operator bool() const noexcept;

    // checked value access

    constexpr void value( boost::source_location const & loc =
      BOOST_CURRENT_LOCATION ) const;

    // unchecked value access

    constexpr void* operator->() noexcept;
    constexpr void const* operator->() const noexcept;

    constexpr void operator*() const noexcept;

    // error access

    constexpr E error() const;

    // emplace

    constexpr void emplace();

    // swap

    constexpr void swap( result& r );
    friend constexpr void swap( result & r1, result & r2 );

    // equality

    friend constexpr bool operator==( result const & r1, result const & r2 );
    friend constexpr bool operator!=( result const & r1, result const & r2 );
};

// stream insertion

template<class Ch, class Tr, class E>
  std::basic_ostream<Ch, Tr>&
    operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r );

} // namespace system
} // namespace boost
Constructors
constexpr result() noexcept;
  • Ensures:

    *this holds an unspecified value.

template<class... A>
  constexpr result( A&&... a );
  • Effects:
    • If std::is_constructible<E, A…​>::value,
      ensures that *this holds the error E( std::forward<A>(a)…​ ).

    • Otherwise, this constructor does not participate in overload resolution.

    Remarks:

    This constructor is only enabled when sizeof…​(T) > 0.

template<class... A>
  constexpr result( in_place_value_t ) noexcept;
  • Ensures:

    *this holds an unspecified value.

template<class... A>
  constexpr result( in_place_error_t, A&&... a );
  • Ensures:

    *this holds the error E( std::forward<A>(a)…​ ).

    Remarks:

    This constructor is only enabled when std::is_constructible<E, A…​>::value is true.

Queries
constexpr bool has_value() const noexcept;
  • Returns:

    true when *this holds a value, false otherwise.

constexpr bool has_error() const noexcept;
constexpr explicit operator bool() const noexcept;
Checked Value Access
constexpr void value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;
  • Effects:

    If *this doesn’t hold a value, calls throw_exception_from_error,
    passing it a reference to the held error, and loc.

Unchecked Value Access
constexpr void* operator->() noexcept;
constexpr void const* operator->() const noexcept;
  • Returns:

    If *this holds a value, a pointer to it. Otherwise, nullptr.

constexpr void operator*() const noexcept;
  • Requires:

    *this holds a value.

    Effects:

    none.

Error Access
constexpr E error() const;
  • Effects:

    If *this holds an error, returns it. Otherwise, returns E().

emplace
constexpr void emplace();
  • Ensures:

    *this holds an unspecified value.

swap
constexpr void swap( result& r );
  • Effects:

    Exchanges the contents of *this and r.

friend constexpr void swap( result & r1, result & r2 );
  • Effects:

    Exchanges the contents of r1 and r2.

Equality
friend constexpr bool operator==( result const & r1, result const & r2 );
  • Effects:
    • If r1 and r2 hold values, returns true.

    • If r1 holds an error e1 and r2 holds an error e2, returns e1 == e2.

    • Otherwise, returns false.

friend constexpr bool operator!=( result const & r1, result const & r2 );
Stream Insertion
template<class Ch, class Tr, class E>
  std::basic_ostream<Ch, Tr>&
    operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r );
  • Effects:
    • If *this holds a value, os << "value:void".

    • If *this holds an error e, os << "error:" << e.

    Returns:

    os.

<boost/system.hpp>

This convenience header includes all the headers previously described.

History

N1975,
Filesystem Library Proposal for TR2, accepted for Library Technical
Report 2 (TR2) at the Berlin meeting, included additional components to
supplement the Standard Library’s Diagnostics clause. Since then, these error
reporting components have received wider public scrutiny and enhancements have
been made to the design. The enhanced version has been used by
N2054,
Networking Library Proposal for TR2, demonstrating that these error reporting
components are useful beyond the original Filesystem Library.

The original proposal viewed error categories as a binary choice between
errno (i.e. POSIX-style) and the native operating system’s error
codes. The proposed components now allow as many additional error categories as
are needed by either implementations or by users. The need to support additional
error categories, for example, occurs in some networking library implementations
because they are built on top of the POSIX getaddrinfo API that
uses error codes not based on errno.

Acknowledgments

Christopher Kohlhoff and Peter Dimov made important contributions to the
design. Comments and suggestions were also received from Pavel Vozenilek,
Gennaro Prota, Dave Abrahams, Jeff Garland, Iain Hanson, Oliver Kowalke, and
Oleg Abrosimov. Christopher Kohlhoff suggested several improvements to the
N2066
paper. Johan Nilsson’s comments led to several of the refinements in N2066.

Copyright and License

This documentation is

  • Copyright 2003-2017 Beman Dawes

  • Copyright 2018-2022 Peter Dimov

boost.png (6897 bytes)

System Library

Introduction

This reference documentation describes components that programs may use to report error conditions originating from the operating
system or other low-level application program interfaces.

Boost.System library components never change the value of
errno
.

C++11

The library is documented to use several C++11 features, including
noexcept
and explicit conversion operators. The actual implementation
uses C++11 features only when they are available, and otherwise falls back on
C++03 features.

Macros

Users may defined the following macros if desired. Sensible defaults are
provided, so users may ignore these macros if they prefer.

Macro Name Default Effect if defined
BOOST_ERROR_CODE_HEADER_ONLY Not defined. The implementation is header-only, and the
Boost.System library is not built. Overrides other link and library macros.
BOOST_SYSTEM_DYN_LINK Defined if BOOST_ALL_DYN_LINK is defined,
otherwise not defined.
Boost.System library is dynamically linked. If not defined,
static linking is assumed.
BOOST_SYSTEM_NO_LIB Defined if BOOST_ALL_NO_LIB is defined,
otherwise not defined.
Boost.System library does not use the Boost auto-link
facility.
BOOST_SYSTEM_NO_DEPRECATED Not defined. Deprecated features are excluded.

Deprecated names

In the process of adding Boost.System to C++0x standard library, the C++
committee changed some
names. To ease transition, Boost.System deprecates the old
names, but continues to provide them unless macro BOOST_SYSTEM_NO_DEPRECATED
is defined.

Old usage, now deprecated Replacement
get_generic_category() generic_category()
get_system_category() system_category()
namespace posix namespace errc
namespace posix_error namespace errc
enum posix_errno enum errc_t
get_posix_category() generic_category()
posix_category generic_category()
errno_ecat generic_category()
native_ecat system_category()

Breaking changes

Two static consts are replaced by functions. These are breaking changes best
fixed by globally adding () to these names to turn them into function calls.

Old usage, now broken Replacement
generic_category generic_category()
system_category system_category()

User-defined BOOST_POSIX_API and BOOST_WINDOWS_API macros are no longer supported.

Header <boost/system/error_code.hpp>

<boost/system/error_code.hpp> synopsis

namespace boost
{
  namespace system
  {
    class error_category;
    const error_category &  system_category() noexcept;
    const error_category &  generic_category() noexcept;

    class error_code;
    class error_condition;

    //  "Concept" helpers
    template< class T="" >
      struct is_error_code_enum { static const bool value = false; };

    template< class T="" >
      struct is_error_condition_enum { static const bool value = false; };

    //  generic error_conditions
    namespace errc
    {
      enum errc_t
      {
        success = 0,
        address_family_not_supported,   //EAFNOSUPPORT
        address_in_use,                 //EADDRINUSE
        address_not_available,          //EADDRNOTAVAIL
        already_connected,              //EISCONN
        argument_list_too_long,         //E2BIG
        argument_out_of_domain,         //EDOM
        bad_address,                    //EFAULT
        bad_file_descriptor,            //EBADF
        bad_message,                    //EBADMSG
        broken_pipe,                    //EPIPE
        connection_aborted,             //ECONNABORTED
        connection_already_in_progress, //EALREADY
        connection_refused,             //ECONNREFUSED
        connection_reset,               //ECONNRESET
        cross_device_link,              //EXDEV
        destination_address_required,   //EDESTADDRREQ
        device_or_resource_busy,        //EBUSY
        directory_not_empty,            //ENOTEMPTY
        executable_format_error,        //ENOEXEC
        file_exists,                    //EEXIST
        file_too_large,                 //EFBIG
        filename_too_long,              //ENAMETOOLONG
        function_not_supported,         //ENOSYS
        host_unreachable,               //EHOSTUNREACH
        identifier_removed,             //EIDRM
        illegal_byte_sequence,          //EILSEQ
        inappropriate_io_control_operation,//ENOTTY
        interrupted,                    //EINTR
        invalid_argument,               //EINVAL
        invalid_seek,                   //ESPIPE
        io_error,                       //EIO
        is_a_directory,                 //EISDIR
        message_size,                   //EMSGSIZE
        network_down,                   //ENETDOWN
        network_reset,                  //ENETRESET
        network_unreachable,            //ENETUNREACH
        no_buffer_space,                //ENOBUFS
        no_child_process,               //ECHILD
        no_link,                        //ENOLINK
        no_lock_available,              //ENOLCK
        no_message_available,           //ENODATA
        no_message,                     //ENOMSG
        no_protocol_option,             //ENOPROTOOPT
        no_space_on_device,             //ENOSPC
        no_stream_resources,            //ENOSR
        no_such_device_or_address,      //ENXIO
        no_such_device,                 //ENODEV
        no_such_file_or_directory,      //ENOENT
        no_such_process,                //ESRCH
        not_a_directory,                //ENOTDIR
        not_a_socket,                   //ENOTSOCK
        not_a_stream,                   //ENOSTR
        not_connected,                  //ENOTCONN
        not_enough_memory,              //ENOMEM
        not_supported,                  //ENOTSUP
        operation_canceled,             //ECANCELED
        operation_in_progress,          //EINPROGRESS
        operation_not_permitted,        //EPERM
        operation_not_supported,        //EOPNOTSUPP
        operation_would_block,          //EWOULDBLOCK
        owner_dead,                     //EOWNERDEAD
        permission_denied,              //EACCES
        protocol_error,                 //EPROTO
        protocol_not_supported,         //EPROTONOSUPPORT
        read_only_file_system,          //EROFS
        resource_deadlock_would_occur,  //EDEADLK
        resource_unavailable_try_again, //EAGAIN
        result_out_of_range,            //ERANGE
        state_not_recoverable,          //ENOTRECOVERABLE
        stream_timeout,                 //ETIME
        text_file_busy,                 //ETXTBSY
        timed_out,                      //ETIMEDOUT
        too_many_files_open_in_system,  //ENFILE
        too_many_files_open,            //EMFILE
        too_many_links,                 //EMLINK
        too_many_synbolic_link_levels,  //ELOOP
        value_too_large,                //EOVERFLOW
        wrong_protocol_type             //EPROTOTYPE
      };

    } // namespace errc

    template<> struct is_error_condition_enum<errc::errc_t>
      { static const bool value = true; };

    //  non-member functions

    bool operator==( const error_code & lhs, const error_code & rhs ) noexcept;
    bool operator==( const error_code & code, const error_condition & condition ) noexcept;
    bool operator==( const error_condition & condition, const error_code & code ) noexcept;
    bool operator==( const error_condition & lhs, const error_condition & rhs ) noexcept;

    bool operator!=( const error_code & lhs, const error_code & rhs ) noexcept;
    bool operator!=( const error_code & code, const error_condition & condition ) noexcept;
    bool operator!=( const error_condition & condition, const error_code & code ) noexcept;
    bool operator!=( const error_condition & lhs, const error_condition & rhs ) noexcept;

    bool operator<( const error_code & lhs, const error_code & rhs ) noexcept;
    bool operator<( const error_condition & lhs, const error_condition & rhs ) noexcept;

    error_code make_error_code( errc::errc_t e ) noexcept;
    error_condition make_error_condition( errc::errc_t e ) noexcept;

    template <class charT, class traits>
      std::basic_ostream<charT,traits>&
        operator<<( basic_ostream<charT,traits>& os, const error_code & ec );

    size_t hash_value( const error_code & ec );
  }
}

The value of each errc_t constant shall be the same as the
value of the <cerrno> macro shown in the above synopsis.

Users may specialize is_error_code_enum and
is_error_condition_enum
templates to indicate that a type is eligible for
class error_code and error_condition automatic
conversions respectively.

const error_category & system_category();

Returns: A reference to a error_category object
identifying errors originating from the operating system.

const error_category & generic_category();

Returns: A reference to a error_category object
identifying portable error conditions.

Class error_category

The class error_category defines the base class for types used
to identify the source and encoding of a particular category of error code.

[Note: Classes may be derived from error_category
to support additional categories of errors. —end note]

The class error_category serves as a base class for types used
to identify the source and encoding of a particular category of error code.
Classes may be derived from error_category to support categories of
errors in addition to those defined in the Boost System library. Such classes
shall behave as specified in this subclause. [ Note: error_category
objects are passed by reference, and two such objects are equal if they have the
same address. This means that applications using custom error_category
types should create a single object of each such type. �end note ]

Class error_category synopsis

namespace boost
{
  namespace system
  {
    class error_category : public noncopyable
    {
    public:
      virtual ~error_category();

      virtual const char *     name() const noexcept = 0;
      virtual string           message( int ev ) const = 0;
      virtual error_condition  default_error_condition( int ev ) const noexcept;
      virtual bool             equivalent( int code, const error_condition & condition )
                                 const noexcept;
      virtual bool             equivalent( const error_code & code, int condition ) const noexcept;

      bool operator==( const error_category & rhs ) const noexcept;
      bool operator!=( const error_category & rhs ) const noexcept;
      bool operator< ( const error_category & rhs ) const noexcept;
    };
  }
}

Class error_category virtual members

Classes derived from error_category shall behave as specified in
this subclause.

virtual const char * name() const noexcept =0;

Returns: a string naming the error category.

virtual string message( int ev ) const noexcept =0;

Returns: A string that describes the error denoted by
ev.

virtual error_condition default_error_condition( int ev ) const noexcept;

Returns:  error_condition( ev, *this ).

 [—Note: Derived classes will typically convert ev
to some portable error_category, such as generic_category(),
and return it as an error_condition for that category. —end
note
]

virtual bool equivalent( int code, const error_condition & condition ) const noexcept;

Returns: default_error_condition( code ) == condition.

virtual bool equivalent( const error_code & code, int condition ) const noexcept;

Returns: *this == code.category() && code.value() == condition.

Class error_category non-virtual members

bool operator==( const error_category & rhs ) const noexcept;

Returns: this == &rhs.

bool operator!=( const error_category & rhs ) const noexcept;

Returns: this != &rhs.

bool operator<( const error_category & rhs ) const noexcept;

Returns: std::less<const error_category*>()( this, &rhs 
noexcept)
.

[Note: std::less provides a total ordering for
pointers. —end note]

Class
error_code

The class error_code describes an object used to hold error code
values, such as those originating from the operating
system or other low-level application program interfaces. [ Note: Class
error_code is an adjunct to error reporting by
exception. �end note ]

Class
error_code
synopsis

namespace boost
{
  namespace system
  {
    class error_code {
    public:

      // constructors:
      error_code() noexcept;
      error_code( val, const error_category & cat ) noexcept;
      template <class ErrorCodeEnum>
        error_code( ErrorCodeEnum e ) noexcept;

      // modifiers:
      void assign( int val, const error_category & cat ) noexcept;
      template<typename ErrorCodeEnum>
        error_code & operator=( ErrorCodeEnum val ) noexcept;
      void clear() noexcept;

      // observers:
      int                    value() const noexcept;
      cont error_category &  category() const noexcept;
      error_condition        default_error_condition() const noexcept;
      string                 message() const;
      operator unspecified-bool-type() const;

    private:
      int val_;                     // exposition only
      const error_category * cat_;  // exposition only
    };
  }
}

Class
error_code
constructors

error_code() noexcept;

Effects: Constructs an object of type error_code.

Postconditions: val_ == 0 && cat_ == &system_category().

error_code( int val, const error_category & cat ) noexcept;

Effects: Constructs an object of type error_code.

Postconditions: val_ == val && cat_ == &cat.

template <class ErrorCodeEnum>
  error_code( ErrorCodeEnum val ) noexcept;

Effects: Constructs an object of type error_code.

Postconditions: *this == make_error_code( val ).

Remarks: This constructor shall not participate in overload
resolution unless is_error_code_enum<ErrorCodeEnum>::value is
true.

Class
error_code
modifiers

void assign( int val, const error_category & cat ) noexcept;

Postconditions: val_ == val && cat_ == &cat.

template<typename ErrorCodeEnum>
  error_code & operator=( ErrorCodeEnum val ) noexcept;

Postconditions: *this == make_error_code( val ).

Remarks: This operator shall not participate in overload resolution
unless is_error_code_enum<ErrorCodeEnum>::value is true.

void clear() noexcept;

postcondition: value() == 0 && category() ==
system_category()

Class
error_code
observers

int value() const noexcept;

Returns: val_.

const error_category & category() const noexcept;

Returns: *cat_.

error_condition default_error_condition() const noexcept;

Returns:  category().default_error_condition( value()).

string message() const;

Returns:  category().message( value()).

Throws: Nothing.

operator unspecified-bool-type() const;

Returns: if value() != 0, returns a value that will evaluate
true in a boolean context; otherwise, returns a value that will
evaluate false in a boolean context. The value type returned shall
not be convertible to int.

Throws: nothing.

[Note: This conversion can be used in contexts where a bool
is expected ( e.g., an if condition ); however, implicit conversions
( e.g., to int) that can occur with bool are not
allowed, eliminating some sources of user error. One possible implementation
choice for this type is pointer-to-member. —end note ]

Class error_condition

The class error_condition describes an object used to hold
values identifying error conditions. [ Note: error_condition
values are portable abstractions, while error_code values are
implementation specific. —end note ]

Class error_condition synopsis

namespace boost
{
  namespace system
  {
    class error_condition
    {
    public:

      // constructors:
      error_condition() noexcept;
      error_condition( int val, const error_category & cat ) noexcept;
      template <class ErrorConditionEnum>
        error_condition( errorConditionEnum val ) noexcept;

      // modifiers:
      void assign( int val, const error_category & cat ) noexcept;
      template<typename ErrorConditionEnum>
        error_condition & operator=( ErrorConditionEnum val ) noexcept;
      void clear() noexcept;

      // observers:
      int value() const noexcept;
      const error_category & category() const noexcept;
      string message() const;
      operator unspecified-bool-type () const noexcept;

    private:
      int val_;                      // exposition only
      const error_category * cat_;   // exposition only
    };
  }
}

Class error_condition
constructors

error_condition() noexcept; 

Effects: Constructs an object of type error_condition.

Postconditions: val_ == 0 and cat_ == &generic_category().

error_condition( int val, const error_category & cat ) noexcept;

Effects: Constructs an object of type error_condition.

Postconditions: val_ == val and cat_ == &cat.

template <class ErrorConditionEnum>
  error_condition( ErrorConditionEnum e ) noexcept;

Effects: Constructs an object of type error_condition.

Postconditions: *this == make_error_condition(e).

Remarks: This constructor shall not participate in overload
resolution unless is_error_condition_enum<ErrorConditionEnum>::value
is true.

Class error_condition
modifiers

void assign( int val, const error_category & cat ) noexcept; 

Postconditions: val_ == val and cat_ == &cat.

template<typename ErrorConditionEnum>
  error_condition & operator=( ErrorConditionEnum e ) noexcept;

Postconditions: *this == make_error_condition( e ).

Returns: *this.

Remarks: This operator shall not participate in overload resolution
unless is_error_condition_enum<ErrorConditionEnum>::value is
true.

void clear() noexcept;

Postcondition: value() == 0 && category() == generic_category()

Class error_condition
observers

int value() const noexcept;

Returns: val_.

const error_category & category() const noexcept;

Returns: *cat_.

string message() const;

Returns: category().message( value() ).

operator unspecified-bool-type () const;

Returns: If value() != 0, returns a value that will
evaluate true in a boolean context; otherwise, returns a value
that will evaluate false. The return type shall not be
convertible to int.

Throws: Nothing.

 [ Note: This conversion can be used in contexts where a bool
is expected ( e.g., an if condition ); however, implicit conversions ( e.g., to
int) that can occur with bool are not allowed,
eliminating some sources of user error. One possible implementation choice for
this type is pointer to member. —end note ]

throws object

extern error_code throws;

The predefined error_code object throws is supplied
for use as a «throw on error» tag.

Semantics of throws object

Functions that specify an argument in the form error_code& ec=throws,
with appropriate namespace qualifiers, have the following error handling
semantics:

Postconditions:

If &ec != &throws and an error occurred:

  • ec.value() returns the implementation specific error
    number for the particular error that occurred.
  • ec.category() returns the
    error_category
    for ec.value().

if &ec != &throws and an error did not occur, ec.clear().

Throws:

If an error occurs and &ec == &throws, throws an exception of type
system_error or of a type
derived from system_error. The
exception’s code() member function returns a reference to an
error_code object with the behavior specified in
Postconditions
.

Non-member functions

bool operator==( const error_code & lhs, const error_code & rhs ) noexcept;

Returns: lhs.category() == rhs.category() && lhs.value() ==
rhs.value()
.

bool operator==( const error_code & code, const error_condition & condition ) noexcept;
bool operator==( const error_condition & condition, const error_code & code ) noexcept;

Returns: code.category().equivalent( code.value(), condition )
|| condition.category().equivalent( code, condition.value() )
.

bool operator==( const error_condition & lhs, const error_condition & rhs ) noexcept;

Returns: lhs.category() == rhs.category() && lhs.value() ==
rhs.value()
.

bool operator!=( const error_code & lhs, const error_code & rhs ) noexcept;

Returns: !(lhs == rhs ).

bool operator!=( const error_code & code, const error_condition & condition ) noexcept;
bool operator!=( const error_condition & condition, const error_code & code ) noexcept;

Returns: !( code ==  condition ).

bool operator!=( const error_condition & lhs, const error_condition & rhs ) noexcept;

Returns: !(lhs == rhs ).

bool operator<( const error_code & lhs, const error_code & rhs ) noexcept;

Returns: lhs.category() < rhs.category()
  || (lhs.category() == rhs.category() && lhs.value() < rhs.value())
.

bool operator<( const error_condition & lhs, const error_condition & rhs ) noexcept;

Returns: lhs.category() < rhs.category()
  || (lhs.category() == rhs.category() && lhs.value() < rhs.value())
.

error_code make_error_code( errc::errc_t e ) noexcept;

Returns: error_code( e, generic_category()).

error_condition make_error_condition( errc::errc_t e ) noexcept;

Returns: error_condition( static_cast<int>( e ), generic_category()).

template <class charT, class traits>
  std::basic_ostream<charT,traits>&
    operator<<( basic_ostream<charT,traits>& os, const error_code & ec );

Effects: os << ec.category().name() << ':' << ec.value().

Returns: os.

size_t hash_value( const error_code & ec );

Returns:  A hash value representing ec.

Header <boost/system/system_error.hpp>

Class
system_error

The class system_error describes an exception object used to
report errors that have an associated error_code. Such errors typically originate from operating system or other low-level
application program interfaces.

namespace boost
{
  namespace system
  {
    class system_error : public std::runtime_error
    {
    public:
      system_error( error_code ec );
      system_error( error_code ec, const char * what_arg );
      system_error( error_code ec, const std::string & what_arg );
      system_error( int ev, const error_category & ecat,
                    const char * what_arg );
      system_error( int ev, const error_category & ecat,
                    const std::string & what_arg );
      system_error( int ev, const error_category & ecat);

      const error_code & code() const throw();
      const char *       what() const throw();
    };
  }
}
system_error( error_code ec );

Effects: Constructs an object of class system_error.

Postcondition: code() == ec
  && std::strcmp( this->runtime_error::what(), "" ) == 0

system_error( error_code ec, const char * what_arg );

Effects: Constructs an object of class system_error.

Postcondition: code() == ec
  && std::strcmp( this->runtime_error::what(), what_arg ) == 0

system_error( error_code ec, const std::string & what_arg );

Effects: Constructs an object of class system_error.

Postcondition: code() == ec
  && std::strcmp( this->runtime_error::what(), what_arg.c_str() ) == 0

system_error( int ev, const error_category & ecat,
             const char * what_arg );

Effects: Constructs an object of class system_error.

Postcondition: code() == error_code( ev, ecat )
  && std::strcmp( this->runtime_error::what(), what_arg ) == 0

system_error( int ev, const error_category & ecat,
             const std::string & what_arg );

Effects: Constructs an object of class system_error.

Postcondition: code() == error_code( ev, ecat )
  && std::strcmp( this->runtime_error::what(), what_arg.c_str() ) == 0

system_error( int ev, const error_category & ecat );

Effects: Constructs an object of class system_error.

Postcondition: code() == error_code( ev, ecat )
  && std::strcmp( this->runtime_error::what(), "" ) == 0

const error_code & code() const;

Returns: ec or error_code( ev, ecat ), from
the constructor, as appropriate.

const char * what() const;

Returns: A string incorporating
this->runtime_error::what()
and
code.message()
.


Revised
January 06, 2014

� Copyright Beman Dawes, 2006, 2007, 2008, 2013

Distributed under the Boost Software License, Version 1.0. See
www.boost.org/LICENSE_1_0.txt

Содержание

  1. Boost.System: Extensible Error Reporting
  2. Introduction
  3. Revision History
  4. Changes in Boost 1.75
  5. Changes in Boost 1.74
  6. Changes in Boost 1.69
  7. Changes in Boost 1.68
  8. Changes in Boost 1.65
  9. Design Rationale
  10. Reference
  11. Use of C++11 and C++14 Features
  12. Macros
  13. Boost.System: Extensible Error Reporting
  14. Introduction
  15. Release History
  16. Changes in Boost 1.69
  17. Changes in Boost 1.68
  18. Changes in Boost 1.65
  19. Design Rationale
  20. Reference
  21. Use of C++11 and C++14 Features
  22. Macros
  23. Boost system error codes
  24. Macros
  25. Deprecated names
  26. Breaking changes
  27. Header
  28. synopsis
  29. Class error_category
  30. Class error_category synopsis
  31. Class error_category virtual members
  32. Class error_category non-virtual members
  33. Class error_category non-member functions
  34. Class error_code
  35. Class error_code synopsis
  36. Class error_code constructors
  37. Class error_code modifiers
  38. Class error_code observers
  39. Class error_condition
  40. Class error_condition synopsis
  41. Class error_condition constructors
  42. Class error_condition modifiers
  43. Class error_condition observers
  44. throws object
  45. Semantics of throws object
  46. Non-member functions
  47. Header
  48. Class system_error

Boost.System: Extensible Error Reporting

Introduction

Error conditions originating from the operating system or other low-level application program interfaces (API’s) are typically reported via an integer representing an error code. When these low-level API calls are wrapped in portable code, such as in a portable library, some users want to deal with the error codes in portable ways. Other users need to get at the system specific error codes, so they can deal with system specific needs. The Boost System library provides simple, light-weight error_code objects that encapsulate system-specific error code values, yet also provide access to more abstract and portable error conditions via error_condition objects.

Because error_code objects can represent errors from sources other than the operating system, including user-defined sources, each error_code and error_condition has an associated error_category .

An exception class, system_error , is provided. Derived from std::runtime_error , it captures the underlying error_code for the problem causing the exception so that this important information is not lost.

While exceptions are the preferred C++ default error code reporting mechanism, users of libraries dependent on low-level API’s often need overloads reporting error conditions via error code arguments and/or return values rather than via throwing exceptions. Otherwise, when errors are not exceptional occurrences and must be dealt with as they arise, programs become littered with try/catch blocks, unreadable, and inefficient. The Boost System library supports both error reporting by exception and by error code.

In addition to portable errors codes and conditions supported by the error_code.hpp header, system-specific headers support the Cygwin, Linux, and Windows platforms. These headers are effectively no-ops if included for platforms other than their intended target.

Boost.System is part of the C++11 Standard Library. A number of changes, particularly to names, were made by the C++ committee during standardization. The Boost implementation has been tracking those changes. See Deprecated Names for synonyms provided to prevent breakage of existing user code.

Revision History

Changes in Boost 1.75

The platform-specific headers windows_error.hpp , linux_error.hpp , and cygwin_error.hpp emit deprecation messages and are slated for removal.

The old names for generic_category() and system_category() emit deprecation messages and are slated for removal.

error_condition::failed is deprecated and is slated for removal. operator bool() for error_condition has been reverted to its old meaning of value() != 0 . This is done for compatibility with std::error_condition as the next release is expected to improve interoperability with even further. Note that this does not affect error_code::failed , which is still alive and well.

The overload of error_condition::message that takes a buffer is deprecated and is slated for removal, for the same reasons. Note that this does not affect error_code::message .

Changes in Boost 1.74

operator bool() now returns failed() instead of value() != 0 .

Changes in Boost 1.69

Boost.System is now header-only. A stub library is still built for compatibility, but linking to it is no longer necessary.

Even more functions have been marked constexpr .

The destructor of error_category is now protected and no longer virtual. This is a potentially breaking change but its impact is expected to be limited.

error_category now has a constructor that accepts a 64 bit identifier, enabling distinct category objects to compare equal.

The constructors of error_category are now protected.

A non-allocating, nonthrowing overload of message has been added.

A virtual function failed has been added, allowing categories for which success is not synonymous with 0.

The deprecated boost::system::throws object has been removed.

boost::throws() is now deprecated and its use is discouraged.

The constructor of system_error taking a single error_code argument is now explicit.

system_error::code() now returns by value.

Changes in Boost 1.68

On a C++14 compiler, many Boost.System functions and member functions are now constexpr , and error_code and error_condition are literal classes.

In addition to enabling use in constant expressions (and constexpr functions), this significantly improves the quality of the generated code.

As a result of this change, however, now using Boost.System from C++14 or C++17 code requires that the library be also built with C++14 or above. This is the default on GCC 6 and newer, but not on GCC 5 or Clang. One can build Boost for C++14 by passing the cxxstd=14 option to b2 .

(Previous versions allowed code built against any C++ standard to link with Boost.System built against any C++ standard. In 1.68, code using any C++ standard can link with Boost.System built with C++14 or above, but if Boost.System is built with C++11 or below, only code also built with C++11 and below can link to it successfully.)

Changes in Boost 1.65

On a C++11 compiler, Boost.System now provides implicit conversions from boost::system::error_category , error_code , and error_condition to their standard equivalents from .

This allows libraries to expose a C++11 interface and report errors via std::error_code even when using Boost.System, directly or through a dependency such as Boost.ASIO.

Design Rationale

error_code and error_condition are designed as value types so they can be copied without slicing and do not require heap allocation, but still have polymorphic behavior based on the error category. This is achieved by abstract base class error_category supplying the polymorphic behavior, and error_code and error_condition containing a pointer to an object of a type derived from error_category .

Many of the detailed design decisions were driven by the requirements that users to be able to add additional error categories, and that it be no more difficult to write portable code than system-specific code.

The operator overload for error_code eliminates a misleading conversion to bool in code like cout , where ec is of type error_code . It is also useful in its own right.

Reference

Use of C++11 and C++14 Features

The library is documented to use several C++11 and C++14 features, including noexcept , explicit conversion operators and constexpr . The actual implementation uses C++11 and C++14 features only when they are available, and otherwise falls back on C++03 features.

Macros

When BOOST_SYSTEM_ENABLE_DEPRECATED is defined, the library provides deprecated features for compatibility. These features are bound to eventually disappear.

When BOOST_SYSTEM_USE_UTF8 is defined, on Windows the library returns UTF-8 messages using code page CP_UTF8 instead of the default CP_ACP . This macro has no effect on POSIX.

Источник

Boost.System: Extensible Error Reporting

Introduction

Error conditions originating from the operating system or other low-level application program interfaces (API’s) are typically reported via an integer representing an error code. When these low-level API calls are wrapped in portable code, such as in a portable library, some users want to deal with the error codes in portable ways. Other users need to get at the system specific error codes, so they can deal with system specific needs. The Boost System library provides simple, light-weight error_code objects that encapsulate system-specific error code values, yet also provide access to more abstract and portable error conditions via error_condition objects.

Because error_code objects can represent errors from sources other than the operating system, including user-defined sources, each error_code and error_condition has an associated error_category .

An exception class, system_error , is provided. Derived from std::runtime_error , it captures the underlying error_code for the problem causing the exception so that this important information is not lost.

While exceptions are the preferred C++ default error code reporting mechanism, users of libraries dependent on low-level API’s often need overloads reporting error conditions via error code arguments and/or return values rather than via throwing exceptions. Otherwise, when errors are not exceptional occurrences and must be dealt with as they arise, programs become littered with try/catch blocks, unreadable, and inefficient. The Boost System library supports both error reporting by exception and by error code.

In addition to portable errors codes and conditions supported by the error_code.hpp header, system-specific headers support the Cygwin, Linux, and Windows platforms. These headers are effectively no-ops if included for platforms other than their intended target.

Boost.System is part of the C++11 Standard Library. A number of changes, particularly to names, were made by the C++ committee during standardization. The Boost implementation has been tracking those changes. See Deprecated Names for synonyms provided to prevent breakage of existing user code.

Release History

Changes in Boost 1.69

Boost.System is now header-only. A stub library is still built for compatibility, but linking to it is no longer necessary.

Even more functions have been marked constexpr .

The destructor of error_category is now protected and no longer virtual. This is a potentially breaking change but its impact is expected to be limited.

error_category now has a constructor that accepts a 64 bit identifier, enabling distinct category objects to compare equal.

The constructors of error_category are now protected.

A non-allocating, nonthrowing overload of message has been added.

A virtual function failed has been added, allowing categories for which success is not synonymous with 0.

The deprecated boost::system::throws object has been removed.

boost::throws() is now deprecated and its use is discouraged.

The constructor of system_error taking a single error_code argument is now explicit.

system_error::code() now returns by value.

Changes in Boost 1.68

On a C++14 compiler, many Boost.System functions and member functions are now constexpr , and error_code and error_condition are literal classes.

In addition to enabling use in constant expressions (and constexpr functions), this significantly improves the quality of the generated code.

As a result of this change, however, now using Boost.System from C++14 or C++17 code requires that the library be also built with C++14 or above. This is the default on GCC 6 and newer, but not on GCC 5 or Clang. One can build Boost for C++14 by passing the cxxstd=14 option to b2 .

(Previous versions allowed code built against any C++ standard to link with Boost.System built against any C++ standard. In 1.68, code using any C++ standard can link with Boost.System built with C++14 or above, but if Boost.System is built with C++11 or below, only code also built with C++11 and below can link to it successfully.)

Changes in Boost 1.65

On a C++11 compiler, Boost.System now provides implicit conversions from boost::system::error_category , error_code , and error_condition to their standard equivalents from .

This allows libraries to expose a C++11 interface and report errors via std::error_code even when using Boost.System, directly or through a dependency such as Boost.ASIO.

Design Rationale

error_code and error_condition are designed as value types so they can be copied without slicing and do not require heap allocation, but still have polymorphic behavior based on the error category. This is achieved by abstract base class error_category supplying the polymorphic behavior, and error_code and error_condition containing a pointer to an object of a type derived from error_category .

Many of the detailed design decisions were driven by the requirements that users to be able to add additional error categories, and that it be no more difficult to write portable code than system-specific code.

The operator overload for error_code eliminates a misleading conversion to bool in code like cout , where ec is of type error_code . It is also useful in its own right.

Reference

Use of C++11 and C++14 Features

The library is documented to use several C++11 and C++14 features, including noexcept , explicit conversion operators and constexpr . The actual implementation uses C++11 and C++14 features only when they are available, and otherwise falls back on C++03 features.

Macros

When BOOST_SYSTEM_ENABLE_DEPRECATED is defined, the library provides deprecated features for compatibility. These features are bound to eventually disappear.

When BOOST_SYSTEM_USE_UTF8 is defined, on Windows the library returns UTF-8 messages using code page CP_UTF8 instead of the default CP_ACP . This macro has no effect on POSIX.

Источник

Boost system error codes

This reference documentation describes components that programs may use to report error conditions originating from the operating system or other low-level application program interfaces.

Boost.System library components never change the value of errno .

Macros

Users may defined the following macros if desired. Sensible defaults are provided, so users may ignore these macros if they prefer.

Macro Name Default Effect if defined
BOOST_SYSTEM_DYN_LINK Defined if BOOST_ALL_DYN_LINK is defined, otherwise not defined. Boost.System library is dynamically linked. If not defined, static linking is assumed.
BOOST_SYSTEM_NO_LIB Defined if BOOST_ALL_NO_LIB is defined, otherwise not defined. Boost.System library does not use the Boost auto-link facility.
BOOST_SYSTEM_NO_DEPRECATED Not defined. Deprecated features are excluded.

Deprecated names

In the process of adding Boost.System to C++0x standard library, the C++ committee changed some names. To ease transition, Boost.System deprecates the old names, but continues to provide them unless macro BOOST_SYSTEM_NO_DEPRECATED is defined.

Old usage, now deprecated Replacement
get_generic_category() generic_category()
get_system_category() system_category()
namespace posix namespace errc
namespace posix_error namespace errc
enum posix_errno enum errc_t
get_posix_category() generic_category()
posix_category generic_category()
errno_ecat generic_category()
native_ecat system_category()

Breaking changes

Two static consts are replaced by functions. These are breaking changes best fixed by globally adding () to these names to turn them into function calls.

Old usage, now broken Replacement
generic_category generic_category()
system_category system_category()

User-defined BOOST_POSIX_API and BOOST_WINDOWS_API macros are no longer supported.

synopsis

The value of each errc_t constant shall be the same as the value of the macro shown in the above synopsis.

Users may specialize is_error_code_enum and is_error_condition_enum templates to indicate that a type is eligible for class error_code and error_condition automatic conversions respectively.

Class error_category

The class error_category defines the base class for types used to identify the source and encoding of a particular category of error code.

[Note: Classes may be derived from error_category to support additional categories of errors. —end note]

The class error_category serves as a base class for types used to identify the source and encoding of a particular category of error code. Classes may be derived from error_category to support categories of errors in addition to those defined in the Boost System library. Such classes shall behave as specified in this subclause. [ Note: error_category objects are passed by reference, and two such objects are equal if they have the same address. This means that applications using custom error_category types should create a single object of each such type. �end note ]

Class error_category synopsis

Class error_category virtual members

Classes derived from error_category shall behave as specified in this subclause.

Returns: a string naming the error category.

Returns: A string that describes the error denoted by ev .

virtual error_condition default_error_condition( int ev ) const;

[—Note: Derived classes will typically convert ev to some portable error_category , such as generic_category() , and return it as an error_condition for that category. —end note]

virtual bool equivalent( int code, const error_condition & condition ) const;

Returns: default_error_condition( code ) == condition .

virtual bool equivalent( const error_code & code, int condition ) const;

Returns: *this == code.category() && code.value() == condition .

Class error_category non-virtual members

bool operator==( const error_category & rhs ) const;

bool operator!=( const error_category & rhs ) const;

[Note: std::less provides a total ordering for pointers. —end note]

Class error_category non-member functions

Returns: A reference to a error_category object identifying errors originating from the operating system.

Returns: A reference to a error_category object identifying portable error conditions.

Class error_code

The class error_code describes an object used to hold error code values, such as those originating from the operating
system or other low-level application program interfaces. [ Note: Class error_code is an adjunct to error reporting by
exception. �end note ]

Class error_code synopsis

Class error_code constructors

Effects: Constructs an object of type error_code .

Postconditions: val_ == 0 && cat_ == &system_category() .

Effects: Constructs an object of type error_code .

Postconditions: val_ == val && cat_ == &cat .

Effects: Constructs an object of type error_code .

Postconditions: *this == make_error_code( val ) .

Remarks: This constructor shall not participate in overload resolution unless is_error_code_enum ::value is true .

Class error_code modifiers

Remarks: This operator shall not participate in overload resolution unless is_error_code_enum ::value is true .

postcondition: value() == 0 && category() == system_category()

Class error_code observers

int value() const;

string message() const;

operator unspecified-bool-type() const;

Returns: if value() != 0 , returns a value that will evaluate true in a boolean context; otherwise, returns a value that will evaluate false in a boolean context. The value type returned shall not be convertible to int .

[Note: This conversion can be used in contexts where a bool is expected ( e.g., an if condition ); however, implicit conversions ( e.g., to int ) that can occur with bool are not allowed, eliminating some sources of user error. One possible implementation choice for this type is pointer-to-member. —end note ]

Class error_condition

The class error_condition describes an object used to hold values identifying error conditions. [ Note: error_condition values are portable abstractions, while error_code values are implementation specific. —end note ]

Class error_condition synopsis

Class error_condition constructors

Effects: Constructs an object of type error_condition .

Postconditions: val_ == 0 and cat_ == &generic_category() .

Effects: Constructs an object of type error_condition.

Postconditions: val_ == val and cat_ == &cat .

Effects: Constructs an object of type error_condition .

Postconditions: *this == make_error_condition(e) .

Remarks: This constructor shall not participate in overload resolution unless is_error_condition_enum ::value is true .

Class error_condition modifiers

Postconditions: *this == make_error_condition( e ) .

Remarks: This operator shall not participate in overload resolution unless is_error_condition_enum ::value is true .

postcondition: value() == 0 && category() == generic_category()

Class error_condition observers

Returns: If value() != 0 , returns a value that will evaluate true in a boolean context; otherwise, returns a value that will evaluate false . The return type shall not be convertible to int .

[ Note: This conversion can be used in contexts where a bool is expected ( e.g., an if condition ); however, implicit conversions ( e.g., to int ) that can occur with bool are not allowed, eliminating some sources of user error. One possible implementation choice for this type is pointer to member. —end note ]

throws object

The predefined error_code object throws is supplied for use as a «throw on error» tag.

Semantics of throws object

Functions that specify an argument in the form error_code& ec=throws , with appropriate namespace qualifiers, have the following error handling semantics:

If &ec != &throws and an error occurred:

  • ec.value() returns the implementation specific error number for the particular error that occurred.
  • ec.category() returns the error_category for ec.value() .

if &ec != &throws and an error did not occur, ec.clear() .

If an error occurs and &ec == &throws , throws an exception of type system_error or of a type derived from system_error . The exception’s code() member function returns a reference to an error_code object with the behavior specified in Postconditions.

Non-member functions

Returns: lhs.category() == rhs.category() && lhs.value() == rhs.value() .

Returns: code.category().equivalent( code.value(), condition )
|| condition.category().equivalent( code, condition.value() ) .

Returns: lhs.category() == rhs.category() && lhs.value() == rhs.value() .

Returns: error_condition( static_cast ( e ), generic_category()) .

Returns: A hash value representing ec .

Class system_error

The class system_error describes an exception object used to report errors that have an associated error_code . Such errors typically originate from operating system or other low-level application program interfaces.

Effects: Constructs an object of class system_error .

Postcondition: code() == ec
&& std::strcmp( this->runtime_error::what(), «» ) == 0

Effects: Constructs an object of class system_error .

Postcondition: code() == ec
&& std::strcmp( this->runtime_error::what(), what_arg ) == 0

Effects: Constructs an object of class system_error .

Postcondition: code() == ec
&& std::strcmp( this->runtime_error::what(), what_arg.c_str() ) == 0

Effects: Constructs an object of class system_error .

Postcondition: code() == error_code( ev, ecat )
&& std::strcmp( this->runtime_error::what(), what_arg ) == 0

Effects: Constructs an object of class system_error .

Postcondition: code() == error_code( ev, ecat )
&& std::strcmp( this->runtime_error::what(), what_arg.c_str() ) == 0

Effects: Constructs an object of class system_error .

Postcondition: code() == error_code( ev, ecat )
&& std::strcmp( this->runtime_error::what(), «» ) == 0

Returns: ec or error_code( ev, ecat ) , from the constructor, as appropriate.

Источник

Just visit: http://www.boost.org/doc/libs/1_55_0/libs/system/doc/reference.html#Header-error_code

enum errc_t {
    success = 0,
    address_family_not_supported,   //EAFNOSUPPORT
    address_in_use,                 //EADDRINUSE
    address_not_available,          //EADDRNOTAVAIL
    already_connected,              //EISCONN
    argument_list_too_long,         //E2BIG
    argument_out_of_domain,         //EDOM
    bad_address,                    //EFAULT
    bad_file_descriptor,            //EBADF
    bad_message,                    //EBADMSG
    broken_pipe,                    //EPIPE
    connection_aborted,             //ECONNABORTED
    connection_already_in_progress, //EALREADY
    connection_refused,             //ECONNREFUSED
    connection_reset,               //ECONNRESET
    cross_device_link,              //EXDEV
    destination_address_required,   //EDESTADDRREQ
    device_or_resource_busy,        //EBUSY
    directory_not_empty,            //ENOTEMPTY
    executable_format_error,        //ENOEXEC
    file_exists,                    //EEXIST
    file_too_large,                 //EFBIG
    filename_too_long,              //ENAMETOOLONG
    function_not_supported,         //ENOSYS
    host_unreachable,               //EHOSTUNREACH
    identifier_removed,             //EIDRM
    illegal_byte_sequence,          //EILSEQ
    inappropriate_io_control_operation,//ENOTTY
    interrupted,                    //EINTR
    invalid_argument,               //EINVAL
    invalid_seek,                   //ESPIPE
    io_error,                       //EIO
    is_a_directory,                 //EISDIR
    message_size,                   //EMSGSIZE
    network_down,                   //ENETDOWN
    network_reset,                  //ENETRESET
    network_unreachable,            //ENETUNREACH
    no_buffer_space,                //ENOBUFS
    no_child_process,               //ECHILD
    no_link,                        //ENOLINK
    no_lock_available,              //ENOLCK
    no_message_available,           //ENODATA
    no_message,                     //ENOMSG
    no_protocol_option,             //ENOPROTOOPT
    no_space_on_device,             //ENOSPC
    no_stream_resources,            //ENOSR
    no_such_device_or_address,      //ENXIO
    no_such_device,                 //ENODEV
    no_such_file_or_directory,      //ENOENT
    no_such_process,                //ESRCH
    not_a_directory,                //ENOTDIR
    not_a_socket,                   //ENOTSOCK
    not_a_stream,                   //ENOSTR
    not_connected,                  //ENOTCONN
    not_enough_memory,              //ENOMEM
    not_supported,                  //ENOTSUP
    operation_canceled,             //ECANCELED
    operation_in_progress,          //EINPROGRESS
    operation_not_permitted,        //EPERM
    operation_not_supported,        //EOPNOTSUPP
    operation_would_block,          //EWOULDBLOCK
    owner_dead,                     //EOWNERDEAD
    permission_denied,              //EACCES
    protocol_error,                 //EPROTO
    protocol_not_supported,         //EPROTONOSUPPORT
    read_only_file_system,          //EROFS
    resource_deadlock_would_occur,  //EDEADLK
    resource_unavailable_try_again, //EAGAIN
    result_out_of_range,            //ERANGE
    state_not_recoverable,          //ENOTRECOVERABLE
    stream_timeout,                 //ETIME
    text_file_busy,                 //ETXTBSY
    timed_out,                      //ETIMEDOUT
    too_many_files_open_in_system,  //ENFILE
    too_many_files_open,            //EMFILE
    too_many_links,                 //EMLINK
    too_many_synbolic_link_levels,  //ELOOP
    value_too_large,                //EOVERFLOW
    wrong_protocol_type             //EPROTOTYPE
};

furthermore:

switch( errcode.value() ) {
    case boost::system::errc::success: {
        // fine
    }
    break;

    case boost::system::errc::operation_canceled: {
        // Timer cancelled
    }
    break;

    default: {
        // Assert unexpected case
    }
    break;
}

namespace boost {
  namespace system {

    class error_category;

    constexpr const error_category & system_category() noexcept;
    constexpr const error_category & generic_category() noexcept;

    class error_code;
    class error_condition;

    // "Concept" helpers

    template<class T>
      struct is_error_code_enum { static const bool value = false; };

    template<class T>
      struct is_error_condition_enum { static const bool value = false; };

    // generic error conditions

    namespace errc {
      enum errc_t
      {
        success = 0,
        address_family_not_supported,   //EAFNOSUPPORT
        address_in_use,                 //EADDRINUSE
        address_not_available,          //EADDRNOTAVAIL
        already_connected,              //EISCONN
        argument_list_too_long,         //E2BIG
        argument_out_of_domain,         //EDOM
        bad_address,                    //EFAULT
        bad_file_descriptor,            //EBADF
        bad_message,                    //EBADMSG
        broken_pipe,                    //EPIPE
        connection_aborted,             //ECONNABORTED
        connection_already_in_progress, //EALREADY
        connection_refused,             //ECONNREFUSED
        connection_reset,               //ECONNRESET
        cross_device_link,              //EXDEV
        destination_address_required,   //EDESTADDRREQ
        device_or_resource_busy,        //EBUSY
        directory_not_empty,            //ENOTEMPTY
        executable_format_error,        //ENOEXEC
        file_exists,                    //EEXIST
        file_too_large,                 //EFBIG
        filename_too_long,              //ENAMETOOLONG
        function_not_supported,         //ENOSYS
        host_unreachable,               //EHOSTUNREACH
        identifier_removed,             //EIDRM
        illegal_byte_sequence,          //EILSEQ
        inappropriate_io_control_operation, //ENOTTY
        interrupted,                    //EINTR
        invalid_argument,               //EINVAL
        invalid_seek,                   //ESPIPE
        io_error,                       //EIO
        is_a_directory,                 //EISDIR
        message_size,                   //EMSGSIZE
        network_down,                   //ENETDOWN
        network_reset,                  //ENETRESET
        network_unreachable,            //ENETUNREACH
        no_buffer_space,                //ENOBUFS
        no_child_process,               //ECHILD
        no_link,                        //ENOLINK
        no_lock_available,              //ENOLCK
        no_message_available,           //ENODATA
        no_message,                     //ENOMSG
        no_protocol_option,             //ENOPROTOOPT
        no_space_on_device,             //ENOSPC
        no_stream_resources,            //ENOSR
        no_such_device_or_address,      //ENXIO
        no_such_device,                 //ENODEV
        no_such_file_or_directory,      //ENOENT
        no_such_process,                //ESRCH
        not_a_directory,                //ENOTDIR
        not_a_socket,                   //ENOTSOCK
        not_a_stream,                   //ENOSTR
        not_connected,                  //ENOTCONN
        not_enough_memory,              //ENOMEM
        not_supported,                  //ENOTSUP
        operation_canceled,             //ECANCELED
        operation_in_progress,          //EINPROGRESS
        operation_not_permitted,        //EPERM
        operation_not_supported,        //EOPNOTSUPP
        operation_would_block,          //EWOULDBLOCK
        owner_dead,                     //EOWNERDEAD
        permission_denied,              //EACCES
        protocol_error,                 //EPROTO
        protocol_not_supported,         //EPROTONOSUPPORT
        read_only_file_system,          //EROFS
        resource_deadlock_would_occur,  //EDEADLK
        resource_unavailable_try_again, //EAGAIN
        result_out_of_range,            //ERANGE
        state_not_recoverable,          //ENOTRECOVERABLE
        stream_timeout,                 //ETIME
        text_file_busy,                 //ETXTBSY
        timed_out,                      //ETIMEDOUT
        too_many_files_open_in_system,  //ENFILE
        too_many_files_open,            //EMFILE
        too_many_links,                 //EMLINK
        too_many_synbolic_link_levels,  //ELOOP
        value_too_large,                //EOVERFLOW
        wrong_protocol_type             //EPROTOTYPE
      };

    } // namespace errc

    template<> struct is_error_condition_enum<errc::errc_t>
      { static const bool value = true; };

    // non-member functions

    constexpr bool operator==( const error_code & lhs,
      const error_code & rhs ) noexcept;
    bool operator==( const error_code & code,
      const error_condition & condition ) noexcept;
    bool operator==( const error_condition & condition,
      const error_code & code ) noexcept;
    constexpr bool operator==( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

    constexpr bool operator!=( const error_code & lhs,
      const error_code & rhs ) noexcept;
    bool operator!=( const error_code & code,
      const error_condition & condition ) noexcept;
    bool operator!=( const error_condition & condition,
      const error_code & code ) noexcept;
    constexpr bool operator!=( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

    constexpr bool operator<( const error_code & lhs,
      const error_code & rhs ) noexcept;
    constexpr bool operator<( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

    constexpr error_code make_error_code( errc::errc_t e ) noexcept;
    constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;

    template <class charT, class traits>
      std::basic_ostream<charT, traits>&
        operator<<( basic_ostream<charT, traits>& os, const error_code & ec );

    std::size_t hash_value( const error_code & ec );

  } // namespace system
} // namespace boost

The value of each errc_t constant is the same as the value of the <cerrno>
macro shown in the above synopsis.

Users may specialize is_error_code_enum and is_error_condition_enum
templates to indicate that a type is eligible for class error_code and
error_condition automatic conversions respectively.

Permalink

Cannot retrieve contributors at this time


This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

Show hidden characters

#ifndef BOOST_SYSTEM_ERROR_CODE_HPP_INCLUDED
#define BOOST_SYSTEM_ERROR_CODE_HPP_INCLUDED
// Copyright Beman Dawes 2006, 2007
// Copyright Christoper Kohlhoff 2007
// Copyright Peter Dimov 2017, 2018
//
// 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)
//
// See library home page at http://www.boost.org/libs/system
#include <boost/system/detail/error_code.hpp>
#include <boost/system/error_category.hpp>
#include <boost/system/error_condition.hpp>
#include <boost/system/errc.hpp>
#include <boost/system/generic_category.hpp>
#include <boost/system/system_category.hpp>
#include <boost/system/detail/throws.hpp>
#endif // BOOST_SYSTEM_ERROR_CODE_HPP_INCLUDED

  • Tutorials
  • Asynchronous I/O with C++
  • Lesson 6

Synchronous functions

Every synchronous I/O function in Boost.Asio has two overloads in order to deal with errors: the first one throws an exception, and the second one returns an error by reference (return value approach).

When Boost.Asio function throws an exception, it throws an instance of boost::system::system_error which is inherited from the std::runtime_error exception class.

To return an error by reference, an instance of boost::system::error_code is used.

Exception approach

try
{
    socket.connect(endpoint);
}
catch(boost::system::system_error const& e)
{
    std::cerr << e.what() << "n";
}

You can retrive the error_code from the system_error by calling code() member function:

catch(boost::system::system_error const& e)
{
    boost::system::error_code error = e.code();
    std::cerr << error.message() << "n";
}

Return value approach

If you don’t want to mess with exceptions, you can use return value overload:

boost::system::error_code error;
socket.connect(endpoint, error);

if(error)
{
    std::cerr << error.message() << "n";
}

Asynchronous functions

Asynchronous I/O functions don’t throw exceptions. They pass boost::system::error_code into a completion handler instead. So, to check if the operation has been successfully completed you should write something like:

socket.async_connect(endpoint, [&] (boost::system::error_code error)
{
    if(!error)
    {
        // Asynchronous operation has been successfully completed
    }
    else
    {
        // Something went wrong
        std::cerr << error.message() << "n";
    }
});

error_code

To get a human-readable error description from the boost::system::error_code you should call message() member funtion which will return std::string with the error description.

If you don’t want to allocate additional std::string instance then you can use message(char const* buffer, std::size_t size) overload.

You can obtain the underlying OS-level error code (which has type int). To do this call value() member function.

If a remote peer close the connection then end-of-file error will be generated. In some cases you don’t want to treat end-of-file error code as an application-level error. For example, if you receive some seamless data from the remote peer, and the peer close the connection, it may be considered as a normal control flow. In that case you could write:

socket.async_receive(buffer, [&] (boost::system::error_code error, std::size_t bytes_transferred)
{
    if(!error)
    {
        // Asynchronous operation has been successfully completed
        // Connection is still alive
    }
    else if(error == boost::asio::error::eof)
    {
        // Connection was closed by the remote peer
        // Still the buffer holds "bytes_transferred" bytes of the received data
    }
    else
    {
        // Something went wrong
        std::cerr << error.message() << "n";
    }
});

Should you pass boost::system::error_code into functions by value or by reference? If you look at Boost.Asio documentation then you’ll see that the library’s author use pass-by-reference approach. However, currentry error_code object consists of one int, one bool and one raw pointer. It is adviced to pass std::string_view by value, which consists of one std::size_t and one raw pointer, which should have the same size (or almost the same size, depends on the target platform) as boost::system::error_code. So, it’s really up to you. In my own code I pass boost::system::error_code by value.

Learning plan

What is server anyway? The most simple example

It’s time to say “goodbye” to a synchronous I/O

The first simple asynchronous TCP server

6. Error handling

How to handle Boost.Asio errors

There are several new things we should learn before jumping into a bigger example of a server

A bigger example of a server where you’ll need to apply everything you’ve learned so far

Principles you should take into consideration during the development of your applications

Понравилась статья? Поделить с друзьями:
  • Bmw f10 ошибка управляемость
  • Bmw f10 ошибка регулировка устойчивости
  • Bmw f10 ошибка 801c20
  • Boost calibration low ошибка
  • Bmw f10 ошибка 26cf00