Doc. no. N2241=07-0101
Date:
2007-04-19
Project: Programming Language C++
Reply to: Beman Dawes <bdawes@acm.org>
Introduction
Design Rationale
History
Acknowledgements
Proposed changes to the Working Paper
Header <system_error>
Class system_error
Class error_category
Class error_code
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. On the other hand, the preferred mechanism for C++ libraries, including the standard library, is to report such errors by throwing an exception. Experience with the progenitors of the Filesystem Library (N1975), the Networking Library (N2054), and with similar Boost libraries has shown that such exceptions need to include the original error code to allow programs to undertake error-condition specific recovery actions.
That experience also found that while exceptions are the preferred default error code reporting mechanism, programs that use libraries dependent on low-level API's 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 very inefficient.
The proposed diagnostic enhancements were originally slated for TR2 (N2066). They are now proposed for C++0x so that they can be used by C++0x threads libraries.
These diagnostic components are packaged in a single header to follow the
standard library's practice of large granularity headers. The components are not simply
added to <stdexcept>
to hold down dependencies in <stdexcept>
.
The header is named <system_error>
to emphasize the role its
contents play, and to emphasize the system_error
exception class.
This is also intended to present class error_code
as an adjunct to
error reporting by exception, rather than a completely separate error handling
mechanism.
error_code
is designed as a value type so it can be copied
without slicing and does not requiring heap allocation, but to
have polymorphic behavior based on the error category. This is achieved by
abstract base class error_category
supplying the polymorphic
behavior, and error_code
containing a pointer to an object of a
type derived from error_category
.
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.
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
.
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
Add to Chapter 19, Diagnostics library [diagnostics], paragraph 2, an additional line in the Diagnostics library summary table, so it reads:
Table 26: Diagnostics library summary
Subclause | Header(s) |
19.1 Exception classes | <stdexcept> |
19.2 Assertions | <cassert> |
19.3 Error numbers | <cerrno> |
19.4 System error support | <system_error> |
Change 19.3, Error numbers [errno], as indicated:
Header <cerrno> (Table 28):
Table 28: Header <cerrno> synopsis
Type: Name(s) |
Macros: E2BIG EACCES EADDRINUSE EADDRNOTAVAIL EAFNOSUPPORT EAGAIN EALREADY EBADF EBADMSG EBUSY ECANCELED ECHILD ECONNABORTED ECONNREFUSED ECONNRESET EDEADLK EDESTADDRREQ EDOM EEXIST EFAULT EFBIG EHOSTUNREACH EIDRM EILSEQ EINPROGRESS EINTR EINVAL EIO EISCONN EISDIR ELOOP EMFILE EMLINK EMSGSIZE ENAMETOOLONG ENETDOWN ENETRESET ENETUNREACH ENFILE ENOBUFS ENODATA ENODEV ENOENT ENOEXEC ENOLCK ENOLINK ENOMEM ENOMSG ENOPROTOOPT ENOSPC ENOSR ENOSTR ENOSYS ENOTCONN ENOTDIR ENOTEMPTY ENOTRECOVERABLE ENOTSOCK ENOTSUP ENOTTY ENXIO EOPNOTSUPP EOTHER EOVERFLOW EOWNERDEAD EPERM EPIPE EPROTO EPROTONOSUPPORT EPROTOTYPE ERANGE EROFS ESPIPE ESRCH ETIME ETIMEDOUT ETXTBSY EWOULDBLOCK EXDEV errno |
The contents are the same as the Standard C
library POSIX header <errno.h>
,
except that errno
shall be defined as a macro,
and an additional macro EOTHER
shall be defined to represent errors
not specified by the POSIX standard.
[Note: The intent is to remain in close alignment with the POSIX standard.
--end note]
Add to Chapter 19, Diagnostics library [diagnostics], the following new subclause. The Project Editor may wish to identify it as 19.4 System error support [sys_err_support.code].
This subclause describes components that the standard library and C++ programs may use to report error conditions originating from the operating system or other low-level application program interfaces.
Component described in this subclause shall not change the value of
errno
([errno]). Implementations are encouraged but not required to leave
unchanged the error states provided by other libraries.
namespace std { class system_error; class error_code; class error_category; extern const error_category& posix_category; extern const error_category& native_category; 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);
enum posix_errno { address_family_not_supported, address_in_use, address_not_available, already_connected, argument_list_too_long, argument_out_of_domain, bad_address, bad_file_descriptor, bad_message, broken_pipe, connection_aborted, connection_already_in_progress, connection_refused, connection_reset, cross_device_link, destination_address_required, device_or_resource_busy, directory_not_empty, executable_format_error, file_exists, file_too_large, filename_too_long, function_not_supported, host_unreachable, identifier_removed, illegal_byte_sequence, inappropriate_io_control_operation, interrupted, invalid_argument, invalid_seek, io_error, is_a_directory, message_size, network_down, network_reset, network_unreachable, no_buffer_space, no_child_process, no_link, no_lock_available, no_message_available, no_message, no_protocol_option, no_space_on_device, no_stream_resources, no_such_device_or_address, no_such_device, no_such_file_or_directory, no_such_process, not_a_directory, not_a_socket, not_a_stream, not_connected, not_enough_memory, not_supported, operation_canceled, operation_in_progress, operation_not_permitted, operation_not_supported, operation_would_block, other, permission_denied, protocol_error, protocol_not_supported, read_only_file_system, resource_deadlock_would_occur, resource_unavailable_try_again, result_out_of_range, stream_timeout, text_file_busy, timed_out, too_many_files_open_in_system, too_many_files_open, too_many_links, too_many_synbolic_link_levels, value_too_large, wrong_protocol_type }; bool operator==(const error_code& ec, posix_errno en); bool operator==(posix_errno en, const error_code& ec); bool operator!=(const error_code& ec, posix_errno en); bool operator!=(posix_errno en, const error_code& ec); }
Predefined objects posix_category
and native_category
identify portable and native error
codes, respectively.
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
.
The meaning and value of each posix_errno
element shall correspond to the equivalent macro from
header <cerrno>
, as defined in the table below.
Name <cerrno> macro 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
other
EOTHER
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
[Note: other
is used to indicate errors
that have no POSIX equivalent. --end note]
system_error
The class system_error
defines the type of objects thrown as
exceptions to report error conditions that have an associated error code. Such
error conditions typically originate from the operating system or other
low-level application program interfaces.
namespace std { class system_error : public std::runtime_error { public: system_error(error_code ec, const std::string& what_arg); system_error(error_code::value_type ev, const error_category& ecat, const std::string& what_arg); const error_code& code() const throw(); const char* what() const throw(); }; }
system_error(error_code ec, const std::string& what_arg);
Effects: Constructs an object of class
system_error
.Postcondition:
code() == ec
&& strcmp( this->runtime_error::what(), what_arg.c_str()) == 0
system_error(error_code::value_type ev, const error_category& ecat, const std::string& what_arg);
Effects: Constructs an object of class
system_error
.Postcondition:
code() == error_code(ev, ecat)
&& strcmp( this->runtime_error::what(), what_arg.c_str()) == 0
const error_code& code() const;
Returns:
ec
orerror_code(ev, ecat)
, from the constructor, as appropriate.
const char* what() const;
Returns: A string incorporating
this->runtime_error::what()
andcode.message()
.[Note: One possible implementation would be:
if (msg.empty()) { try { msg = this->runtime_error::what(); if ( code() ) { if ( !msg.empty() ) msg += ": "; msg += code().message(); } } catch (...) { return runtime_error::what(); } } return msg.c_str();--end note]
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]
namespace std { class error_category { public: virtual const std::string & name() const=0; virtual posix_errno posix(error_code::value_type ev) const=0; virtual string message(error_code::value_type ev) const=0; virtual wstring wmessage(error_code::value_type ev) const=0; bool operator==(const error_category& rhs) const; bool operator!=(const error_category& rhs) const; }; }
error_category
virtual membersClasses derived from error_category
shall behave as specified in
this subclause.
virtual const std::string & name() const=0;
Returns: a string naming the error category.
Throws: Nothing.
virtual posix_errno posix(error_code::value_type ev) const=0;
Returns: A
posix_errno
that corresponds toev
if such a corresponding POSIX error number exists, otherwiseother
.[Note: Since the value of
ev
is not bounded, the intent is that implementations translate commonly encountered values to the equivalent POSIX error number and translate the rest toother
. --end note]Throws: Nothing.
virtual string message(error_code::value_type ev) const=0;
Returns: A string that describes the error condition denoted by
ev
.[Note: The intent is to return a locale sensitive string that describes the error corresponding to
ev
. --end note.]Throws: Nothing.
virtual wstring wmessage(error_code::value_type ev) const=0;
Returns: A string that describes the error condition denoted by
ev
.[Note: The intent is to return a locale sensitive string that describes the error corresponding to
ev
. --end note.]Throws: Nothing.
error_category
non-virtual membersbool operator==(const error_category& rhs) const;
Returns:
this == &rhs
.
bool operator!=(const error_category& rhs) const;
Returns:
this != &rhs
.
error_code
The class error_code
defines the type of objects 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
as an adjunct to
error reporting by exception, rather than a completely separate error handling
mechanism. --end note.]
namespace std { class error_code { public: typedef int_least32_t value_type; // constructors: error_code(); error_code(value_type val, const error_category& cat); error_code(posix_errno val); // modifiers: void assign(value_type val, const error_category& cat); error_code& operator=(posix_errno val); void clear(); // observers: value_type value() const; const error_category& category() const; posix_errno posix() const; string message() const; wstring wmessage() const; operator unspecified-bool-type() const; // relationals: bool operator==(const error_code& rhs) const; bool operator!=(const error_code& rhs) const; private: value_type _val; // for exposition only const error_category* _cat; // for exposition only }; }
error_code
memberserror_code();
Effects: Constructs an object of type
error_code
.Postconditions:
_val == 0 && _cat == &posix_category
.Throws: Nothing.
error_code(value_type val, const error_category& cat);
Effects: Constructs an object of type
error_code
.Postconditions:
_val == val && _cat == &cat
.Throws: Nothing.
error_code(posix_errno val);
Effects: Constructs an object of type
error_code
.Postconditions:
_val == static_cast<value_type>(val) && _cat == &posix_category
.Throws: Nothing.
void assign(value_type val, const error_category& cat);
Postconditions:
_val == val && _cat == &cat
.Throws: Nothing.
error_code& operator=(posix_errno val);
Postconditions:
_val == static_cast<value_type>(val) && _cat == &posix_category
.Throws: Nothing.
value_type value() const;
Returns:
_val
.Throws: Nothing.
error_category category() const;
Returns:
_cat
.Throws: Nothing.
posix_errno posix() const;
Returns:
category().posix(value())
.Throws: Nothing.
string message() const;
Returns:
category().message(value())
.Throws: Nothing.
wstring wmessage() const;
Returns:
category().wmessage(value())
.Throws: Nothing.
operator unspecified-bool-type() const;
Returns: if
value() != value_type()
, returns a value that will evaluatetrue
in a boolean context; otherwise, returns a value that will evaluatefalse
in a boolean context. The value type returned shall not be convertible toint
.Throws: nothing.
[Note: This conversion can be used in contexts where a
bool
is expected (e.g., anif
condition); however, implicit conversions (e.g., toint
) that can occur withbool
are not allowed, eliminating some sources of user error. One possible implementation choice for this type is pointer-to-member. —end note ]
bool operator==(const error_code& rhs) const;
Returns:
value() == rhs.value() && category() == rhs.category()
.Throws: Nothing.
bool operator!=(const error_code& rhs) const;
Returns:
!(*this == rhs)
.Throws: Nothing.
bool operator==(const error_code& ec, posix_errno en);
bool operator==(posix_errno en, const error_code& ec);
Returns:
ec.value() == static_cast<error_code::value_type>(en) && ec.category() == &posix_category
Throws: Nothing.
bool operator!=(const error_code& ec, posix_errno en);
bool operator!=(posix_errno en, const error_code& ec);
Returns:
!(ec==en)
Throws: Nothing.