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_supportedEAFNOSUPPORTaddress_in_useEADDRINUSEaddress_not_availableEADDRNOTAVAILalready_connectedEISCONNargument_list_too_longE2BIGargument_out_of_domainEDOMbad_addressEFAULTbad_file_descriptorEBADFbad_messageEBADMSGbroken_pipeEPIPEconnection_abortedECONNABORTEDconnection_already_in_progressEALREADYconnection_refusedECONNREFUSEDconnection_resetECONNRESETcross_device_linkEXDEVdestination_address_requiredEDESTADDRREQdevice_or_resource_busyEBUSYdirectory_not_emptyENOTEMPTYexecutable_format_errorENOEXECfile_existsEEXISTfile_too_largeEFBIGfilename_too_longENAMETOOLONGfunction_not_supportedENOSYShost_unreachableEHOSTUNREACHidentifier_removedEIDRMillegal_byte_sequenceEILSEQinappropriate_io_control_operationENOTTYinterruptedEINTRinvalid_argumentEINVALinvalid_seekESPIPEio_errorEIOis_a_directoryEISDIRmessage_sizeEMSGSIZEnetwork_downENETDOWNnetwork_resetENETRESETnetwork_unreachableENETUNREACHno_buffer_spaceENOBUFSno_child_processECHILDno_linkENOLINKno_lock_availableENOLCKno_message_availableENODATAno_messageENOMSGno_protocol_optionENOPROTOOPTno_space_on_deviceENOSPCno_stream_resourcesENOSRno_such_device_or_addressENXIOno_such_deviceENODEVno_such_file_or_directoryENOENTno_such_processESRCHnot_a_directoryENOTDIRnot_a_socketENOTSOCKnot_a_streamENOSTRnot_connectedENOTCONNnot_enough_memoryENOMEMnot_supportedENOTSUPoperation_canceledECANCELEDoperation_in_progressEINPROGRESSoperation_not_permittedEPERMoperation_not_supportedEOPNOTSUPPoperation_would_blockEWOULDBLOCKotherEOTHERowner_deadEOWNERDEADpermission_deniedEACCESprotocol_errorEPROTOprotocol_not_supportedEPROTONOSUPPORTread_only_file_systemEROFSresource_deadlock_would_occurEDEADLKresource_unavailable_try_againEAGAINresult_out_of_rangeERANGEstate_not_recoverableENOTRECOVERABLEstream_timeoutETIMEtext_file_busyETXTBSYtimed_outETIMEDOUTtoo_many_files_open_in_systemENFILEtoo_many_files_openEMFILEtoo_many_linksEMLINKtoo_many_synbolic_link_levelsELOOPvalue_too_largeEOVERFLOWwrong_protocol_typeEPROTOTYPE
[Note: other is used to indicate errors
that have no POSIX equivalent. --end note]
system_errorThe 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:
ecorerror_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_categoryThe 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_errnothat corresponds toevif such a corresponding POSIX error number exists, otherwiseother.[Note: Since the value of
evis 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_codeThe 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 evaluatetruein a boolean context; otherwise, returns a value that will evaluatefalsein a boolean context. The value type returned shall not be convertible toint.Throws: nothing.
[Note: This conversion can be used in contexts where a
boolis expected (e.g., anifcondition); however, implicit conversions (e.g., toint) that can occur withboolare 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_categoryThrows: Nothing.
bool operator!=(const error_code& ec, posix_errno en);
bool operator!=(posix_errno en, const error_code& ec);
Returns:
!(ec==en)Throws: Nothing.