This paper details possible corrections to the error handling and diagnostics machinery detailed in N2241, which was voted into the working draft for C++0x at the Oxford meeting. In particular, it advocates replacing all of section 19.4 in the working draft with the text below.
namespace std { struct error_catalog; struct system_error; }
error_catalog
The class error_catalog
is a std::locale
aware map between a positive integer numeric value and a
null-terminated character sequence providing an elaborated description
of the specific error. It is designed for exception-safe use, with the
only possible exception path being the non-default constructor for
named locales. In particular, all member function operations after
construction are exception-free.
It is assumed that all the system-level error conditions needed to build C++0x library facilities will be represented in this class as compile-time data members. This provides a safer nested scope for compile-time querying, and less compressed identifiers than the equivalent C or POSIX macros.
namespace std { struct error_catalog { typedef int value_type; static const value_type address_family_not_supported = EAFNOSUPPORT; static const value_type address_in_use = EADDRINUSE; static const value_type address_not_available = EADDRNOTAVAIL; static const value_type already_connected = EISCONN; static const value_type argument_list_too_long = E2BIG; static const value_type argument_out_of_domain = EDOM; static const value_type bad_address = EFAULT; static const value_type bad_file_descriptor = EBADF; static const value_type bad_message = EBADMSG; static const value_type broken_pipe = EPIPE; static const value_type connection_aborted = ECONNABORTED; static const value_type connection_refused = ECONNREFUSED; static const value_type connection_reset = ECONNRESET; static const value_type cross_device_link = EXDEV; static const value_type destination_address_required = EDESTADDRREQ; static const value_type device_or_resource_busy = EBUSY; static const value_type directory_not_empty = ENOTEMPTY; static const value_type executable_format_error = ENOEXEC; static const value_type file_exists = EEXIST; static const value_type file_too_large = EFBIG; static const value_type filename_too_long = ENAMETOOLONG; static const value_type function_not_supported = ENOSYS; static const value_type host_unreachable = EHOSTUNREACH; static const value_type identifier_removed = EIDRM; static const value_type illegal_byte_sequence = EILSEQ; static const value_type inappropriate_io_control_operation =ENOTTY; static const value_type interrupted = EINTR; static const value_type invalid_argument = EINVAL; static const value_type invalid_seek = ESPIPE; static const value_type io_error = EIO; static const value_type is_a_directory = EISDIR; static const value_type message_too_long = EMSGSIZE; static const value_type network_down = ENETDOWN; static const value_type network_reset = ENETRESET; static const value_type network_unreachable = ENETUNREACH; static const value_type no_buffer_space = ENOBUFS; static const value_type no_child_process = ECHILD; static const value_type no_link = ENOLINK; static const value_type no_lock_available = ENOLCK; static const value_type no_message_available = ENODATA; static const value_type no_message = ENOMSG; static const value_type no_space_on_device = ENOSPC; static const value_type no_stream_resources = ENOSR; static const value_type no_such_device_or_address = ENXIO; static const value_type no_such_device = ENODEV; static const value_type no_such_file_or_directory = ENOENT; static const value_type no_such_process = ESRCH; static const value_type not_a_directory = ENOTDIR; static const value_type not_a_socket = ENOTSOCK; static const value_type not_a_stream = ENOSTR; static const value_type not_connected = ENOTCONN; static const value_type not_enough_memory = ENOMEM; static const value_type not_supported = ENOTSUP; static const value_type operation_already_in_progress = EALREADY; static const value_type operation_canceled = ECANCELED; static const value_type operation_in_progress = EINPROGRESS; static const value_type operation_not_permitted = EPERM; static const value_type operation_not_supported = EOPNOTSUPP; static const value_type owner_dead = EOWNERDEAD; static const value_type permission_denied = EACCES; static const value_type protocol_error = EPROTO; static const value_type protocol_not_available = ENOPROTOOPT; static const value_type protocol_not_supported = EPROTONOSUPPORT; static const value_type read_only_file_system = EROFS; static const value_type resource_deadlock_would_occur = EDEADLK; static const value_type result_out_of_range = ERANGE; static const value_type state_not_recoverable = ENOTRECOVERABLE; static const value_type stream_timeout = ETIME; static const value_type text_file_busy = ETXTBSY; static const value_type timed_out = ETIMEDOUT; static const value_type too_many_files_open_in_system = ENFILE; static const value_type too_many_files_open = EMFILE; static const value_type too_many_links = EMLINK; static const value_type too_many_synbolic_link_levels = ELOOP; static const value_type try_again = EAGAIN; static const value_type value_too_large = EOVERFLOW; static const value_type wrong_protocol_type; = EPROTOTYPE; virtual const value_type last_value() const throw(); virtual bool is_valid_value(value_type) const throw(); virtual const char* str(value_type) const throw(); const locale& getloc() const throw(); error_catalog(const locale& __loc = locale::classic()) throw(); error_catalog(const char* __name); virtual ~error_catalog() throw(); bool operator==(const error_catalog&) const throw(); bool operator!=(const error_catalog&) const throw(); private: const locale _M_loc; }; }
Defined values for the const static data members of this class are all non-zero, positive integer values.
Changes from N2241 are: change
resource_unavailable_try_again
to try_again
,
no_protocol_option
to
protocol_not_available
,
connection_already_in_progress
to
operation_already_in_progress
, message_size
to message_too_long
. In addition, remove
operation_would_block
and other
.
Definitions for the member functions of this class are as follows. Please note, the requirements for virtual member functions are the same for the base class and any derived classes.
virtual const value_type last_value() const throw();
Returns: A
const value_type
representing the largest valuen
such thatis_valid_value(n)
istrue
.
virtual bool is_valid_value(value_type __n) const throw();
Returns: If the argument
__n
is equal to any of the static constant data members oferror_catalog
, thentrue
, elsefalse
.
virtual const char* str(value_type __n) const throw();
Returns: If
is_valid_value(__n)
, returns a null-terminated character sequence corresponding to__n
in thestd::locale
that would be returned bygetloc
, else an empty string (ie,""
).Note: An example of the expected behavior is as follows.
std::locale loc; std::string s; try { loc = std::locale("fr_FR"); } catch(...) { // Construction of named locale didn't work. } std::error_catalog e1(loc); s = e1.str(std::error_catalog::file_exists); bool b1 = s == "Le fichier existe."; std::error_catalog e2; s = e2.str(std::error_catalog::file_exists); bool b2 = s == "File exists";
const locale& getloc() const throw();
Returns: A
const std::locale
reference to the current locale of theerror_catalog
instance.
error_catalog(const char* __name);
Effects: Construct an
error_catalog
object localized for thestd::locale
named by theconst char*
argument.Postcondition:
getloc() == std::locale(__name)
.Throws: If
__name
is not a valid name, construction ofstd::locale
could fail, which may throwstd::runtime_error
.Note: Valid names could be
"POSIX"
or"C"
, or any other implementation-defined-as-valid string.
error_catalog(const locale& __loc) throw();
Effects: Construct an
error_catalog
object localized for thestd::locale
named by the__loc
argument. The default argument isstd::locale::classic()
Postcondition:
getloc() == __loc
.
bool operator==(const error_catalog& __other) const throw();
Returns: If
getloc() == __other.getloc()
andtypeinfo(*this) == typeinfo(__other)
, then returntrue
. Else returnfalse
.
bool operator!=(const error_catalog& __other) const throw();
Returns:
!(*this == __other)
system_error
The class system_error
is an exception derived from
std::runtime_error
that is designed to be useful for
reporting the detailed character sequences corresponding to a given
error_catalog
and error_catalog::value_type
.
namespace std { class system_error : public std::runtime_error { public: system_error(const string&); system_error(error_catalog::value_type, const error_catalog&); }; }
Definitions for the member functions of this class are as follows.
system_error(const string& __s);
Postcondition:
strcmp(what(), __s.c_str()) == 0
.
error_catalog(error_catalog::value_type __v, const error_catalog& __cat);
Postcondition:
strcmp(what(), __cat.str(__v)) == 0
.
The standard components detailed above are designed so that
consumers of system_error
will be able to extend
namespace std
components for non-standard domains.
As a example of extensibility, here's a demonstration of an
non-localized set of new error conditions, perhaps for a inkjet
printer, implemented as a derived class of
error_catalog
. As can be seen, it's quite
straightforward.
namespace __gnu_test { struct derived_error_catalog : virtual public std::error_catalog { typedef std::error_catalog base_type; static const value_type out_of_ink = 20001; static const value_type out_of_paper = 20002; virtual bool is_valid_value(value_type __v) const throw() { bool ret = false; if (base_type::is_valid_value(__v)) ret = true; else { if (__v == out_of_ink || __v == out_of_paper) ret = true; } return ret; } virtual const char* str(value_type __v) const throw() { const char* s = NULL; const char* s1 = "Out of Ink"; const char* s2 = "Out of Paper"; if (is_valid_value(__v)) { if (base_type::is_valid_value(__v)) s = base_type::str(__v); else { switch (__v) { case out_of_ink: s = s1; break; case out_of_paper: s = s2; break; default: s; } } } return s; } virtual const value_type last_value() const throw() { return out_of_paper; } }; }
The code below is but one example: it would be possible for
operating system vendors to derive os-specific error catalogs. (For
instance, a possible Microsoft extension could conceivably be
win_error_catalog
, with the requisite sixteen thousand
constants mapped to locale-specific error strings.)
Another possibility for extensions to error_catalog
would be a derived class for user-specified wide-character messages.
In this way it would be possible for users to specify unicode (or
other encoding) messages for either the standard error conditions or
some extended catalog of error conditions, without bogging down the
required system behavior.
Ulrich Drepper commented on draft versions of this paper, sanity
checked C
and POSIX
usage, suggested better
semantics for testing equality, and championed the strongest possible
exception specifications.
Diagnostics Enhancements for C++0x (Rev. 1)
Becker, Pete, Working Draft, Standard for Programming Language C++, N2284=07-0144