Benjamin Kosnik
Document number: N2309=07-0169
2007-06-21

Error-handling and Exception-related library changes for C++0x

This paper outlines changes in the way std::exception and derived classes are designed and used in the draft C++0x library. It attempts to survey existing C++ practice, and detail defects in the C++03 standard that have risen to the surface after almost a decade of use. As such, it falls into the categories of removing embarrassments, increasing consistency, and making C++ easier to teach and learn.

Changes to support compiling C++ with and without exceptions.

In the last decade, all implementations of the C++ standard library have had to design modes such that the library is compilable without exception handling enabled, and all compilers of the C++ language have flags for turning off exception support. A quick look at other major C++ libraries such as Boost, ACE, and others show similar scars. It is not necessary to argue why this is so, if the performance differences between exception enabled and exception disabled code is measurable or significant, if this is a preference or a religion, a practice based in fact or fiction.

Instead, a new tack: confronting reality. Apparently, not every C++ user is willing to pay for all costs of the full language, and exceptions impose a cost unconditionally on many widely available toolchains.

Implementations for a library capable of being compiled both with and without exception support and are divided into two major concerns: what to do about the actual throw expressions (and the related exception classes), and what to do with control flow (the try and catch blocks).

For the first concern, all implementations seem to have similar approaches: the creation of an include file that has function declarations for throwing each of the exception classes defined in the standard, and for re-throwing exception classes. This is a possible candidate for standardization. (Another approach is elaborated below, whereby a level of indirection is inserted between raising an error and the actual throw expression, where the throw expression is optional if compiling without exception support.)

It is an open question if alternate error and diagnostic frameworks such as found in <system_error> could be integrated into this solution such that the no-exceptions code paths still have some kind of error checking.

The second concern has less uniform solutions: some implementations transform try and catch blocks into #if 1 and #if 0 blocks when compiling without exceptions at the pre-processor level, others macro-ize all try and catch blocks, and do pre-processing to convert to try and catch blocks when compiling with exceptions and something else when compiling without exceptions. Standardizing this behavior seems like a less likely candidate for library standardization, but perhaps a language solution exists. If existing compiler support for compilation of C++ without exceptions could be standardized, or even made optional or a measure of QoI, this issue could be handily solved. It would be better, however, if existing (minimal) support was modified such that transformation of try and catch was done as part of the (non pre-processor) compilation process, and not via a library solution. The end goal of this modification would improve legibility, by allowing unconditional use of existing C++ try and catch syntax, but transforming it to some benign form in the absence of true exception support.

Changes to the exception classes and hierarchy

Several areas of improvement come to mind.

Consistent naming.

Consistent naming of exception classes, library wide. Pick _error suffix, or bad_ prefix, or invent something new, but suggest a common naming scheme that all exception classes follow. As part of this, the exception base class should have _base suffix.

Remove duplicates and inconsistencies.

Removal of warts and inconsistencies in current logic and design. For instance, all exceptions force a stack unwind, which can only occur at runtime, yet there is runtime_error. Why? The io exception (ios_base::failure) is a nested class, yet none of the other exceptions are. Why? The end goal would be to design exception classes for the standard library that Bjarne wouldn't savage in his books.

Remove duplication between <system_error> components thrown by not_enough_memory and the existing bad_alloc, or io_error and the existing ios_base::failure, etc. This could take the form of removing the system_error exception class, or integrating its functionality into exception, or some other solution.

Make one-to-one map of exception classes to error codes.

Make sure that there is a one-to-one mapping between the diagnostic codes in <system_error> and exception classes in <stdexcept>. Giving all errors a one-to-one match with exceptions will allow mapping between error/diagnostic constants and exception classes. (And thus coherent error handling between exception-enabled and exception-disabled source code.)

Virtual derivation.

Change derivation to be virtual public for exception hierarchy. This would match other parts of the existing library design for class hierarchies, such as ostream and istream deriving virtual public from basic_ios. There are at least two advantages of this change:

1. Third derivations are now unambiguous. Example (modification of the issue detailed by David Abrahams).

#include <stdexcept>

struct bad_non_virtual : virtual public std::exception { };

struct diamond_error : std::bad_exception, bad_non_virtual { };

int main()
{
  try
    {
      throw diamond_error();
    }
  catch (const std::exception&)
    { 
      // Fails, ambiguous.
    }
  catch (...)
    {
      // Match.
    }
  return 0;
}

2. Allows new exception designs and functionality. For instance, could add in exception classes such as re-throwable or concurrent, and use in more complex hierarchies instead of declaring subject-specific exception classes. Ie, instead of io_lock_error one could derive an io_error, that optionally had a concurrent_error.

struct base 
{ virtual ~base() { } };

struct always_rethrow_error : virtual public base { };

struct concurrent_error : virtual public base { };

struct io_error : public concurrent_error, always_rethrow_error { };


int main()
{
  try
    {
      throw io_error();
    }
  catch (const base& obj)
    {
      try
	{ throw; }
      catch (always_rethrow_error&)
	{
	  throw; 
	}
      catch (...)
	{
	  // Other error handling, swallow.
	}
    }
  return 0;
}

This example is but one demonstration (and not perhaps the best choice for determining if a particular exception is re-throwable).

Standardizing what() strings.

All of the NTBS return values for exception::what() are implementation-defined. This causes problems for portable code that parses the returned string.

Baby steps toward this goal could include mandating that all return values start with the name of the most-derived exception class at construction, perhaps optionally followed by the explicitly qualified scope of the throw site. After that, the choices for messages start to diverge rapidly.

Nevertheless, just these simple steps would make text parsing of exception error messages possible in a portable way.

Add more data.

Integrate necessary changes for new C++0x components like diagnostics and threads, and missing functionality. Two areas that demand attention are: a mechanism for marking exception objects as always re-thrown from catch blocks, and a way to map diagnostic/error numerical constants to the associated exception classes (and back again.)

To mark exception objects as always-re-thrown, a variety of solutions exist. The first would be to add a member, say something like:

virtual const bool
is_rethrown() const throw() { return true; }

A second option would be to use multiple inheritance to establish a base exception class that was re-throwable, and inherit from it for exceptions that are to be re-thrown. See the example above, in the discussion of Virtual derivation.

For the second issue, mapping diagnostic/error constants to exception classes, possible solutions include adding a member function to the exception base class, similar to what(), but instead returning the associated numerical constant. An example:

virtual const int
value() const throw();

Another item in the solution space for the mapping issue would be to have a global map or function that takes an error code and returns an exception.

template<typename _Exception>
_Exception
use_exception(int error_code, std::string& msg);

This has the advantage that it could be extended by users by specialization, and would not take up space in the virtual table of a (more complicated) exception class hierarchy.

Changes to include files.

A more coherent include policy.

<system_error> (or perhaps <error_constants>), as specified in N2303, minus any exception classes, and in particular system_error, as it is subsumed into the expanded standard class hierarchies. If possible, make only external dependency std::locale forward declaration.

<exception> (or perhaps <exceptionfwd>), containing C++03 contents, minus any exception classes, with the one exception of the exception_base class. In addition, move nothrow_t from <new> to this file. No <string> dependencies.

<stdexception>, all derived exception classes with <string> dependencies, one-to-one match with error constants detailed in <system_error>. Current exception classes scattered throughout C++0x include files would be eliminated in favor of equivalent exception classes from the expanded hierarchy, including bad_alloc, bad_typeid, bad_cast, bad_exception, bad_function_call, and ios_base::failure.

<exception_utils> (or perhaps <exceptionmanip>), containing utilities for mapping between exception and exception-free code, namely mapping between error constants and the equivalent exception objects.

Please see the Appendix for example header files that implement the suggestions above.

Changes to catch blocks: ending the swallowed exceptions practice.

Some implementations of POSIX thread cancellation use the same frame unwind machinery as C++ exception handling implementations. Invariably, conflicts can occur. Sorting this out intelligently, so that both can co-exist is a matter of some debate.

Various solutions have been proposed.

1. Deprecating catch(...) that doesn't re-throw. The C++03 io code is notorious for this.

2. Changing catch(...) to instead only catch exception objects mandated in the standard, ie catch(const std::exception&)

3. A magic internal exception type, that can be re-thrown by relevant catch blocks when encountered.

4. Suggestions have been made for a handler function, that would make catch clauses re-throw. Or, in a similar vein, modifying member functions like basic_ios::exceptions that have a user-controlled mechanism for determining if exceptions are ignored or active, to also have a third state which controls re-throw behavior.

5. Deal with this in the catch block, using properties of the exception object being thrown and caught.

Whichever mechanism it picked, the entire C++0x library should be audited to make sure that the exception and error handling is consistent.

Making io error checking internally consistent, and externally consistent with new diagnostic machinery.

This involves the detailed implementation of a library-wide effort to do apply the above ideas.

All catch statements would need to be evaluated. If the exception object demanded to be re-thrown, then it would be (after possibly setting some error state or condition in the host object or associated area of said catch statement.

The application of whatever solution was accepted for exception/exception-free code would have to be done, library-wide.

Adding new exception handling features, ie finally.

Not covered in this document.

Acknowledgments

Ulrich Drepper, Pete Dimov, and other posters on the GNU libstdc++ mailing list.

References

Diagnostics Enhancements for C++0x (Rev. 1)

Diagnostics Enhancements; Resolution of Small Issues

Revised system_error (Revision 2)

Becker, Pete, Working Draft, Standard for Programming Language C++, N2284=07-0144

Abrahams, David, Error and Exception Handling

Stroustrup, Bjarne, The C++ Programming Language, v3. Chapter 14, Exception Handling.

Sutter, Herb, Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions, Chaper "Exception-Safety Issues and Techniques"

Sutter, Herb, More Exceptional C++, Chaper "Exception-Safety Issues and Techniques"

Gosling, Jame (Bill Joy, Guy Steele, Gilad Bracha), Java Language Specification, Third Edition

Appendix

<system_error>

#ifndef _SYSTEM_ERROR
#define _SYSTEM_ERROR 1

#include <cerrno>
#include <locale>
#include <typeinfo>

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 = 	   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 = 			   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_canceled = 	   ECANCELED;
    static const value_type operation_in_progress = 	   EINPROGRESS;
    static const value_type operation_already_in_progress = EALREADY;
    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 = 		   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
    { return _M_loc; }

    error_catalog(const char* __name) : _M_loc(__name) 
    { locale::facet::_S_create_c_locale(_M_c_locale, __name); }

    error_catalog(const locale& __loc = locale::classic()) throw() 
    : _M_loc(__loc) 
    { locale::facet::_S_create_c_locale(_M_c_locale, __loc.name().c_str()); }

    virtual ~error_catalog() throw();

    bool 
    operator==(const error_catalog& __other) const throw()
    { 
      bool __ret = getloc() == __other.getloc();
      __ret &= typeid(*this) == typeid(__other);
      return __ret;
    }

    bool 
    operator!=(const error_catalog& __other) const throw()
    { return !(*this == __other); }

  private:
    const locale	_M_loc;
  };
} // namespace std

#endif // _SYSTEM_ERROR

<exception>

#fndef _EXCEPTION
#define _EXCEPTION 1

namespace std
{
  typedef void (*terminate_handler) ();
  typedef void (*unexpected_handler) ();

  terminate_handler set_terminate(terminate_handler) throw();
  unexpected_handler set_unexpected(unexpected_handler) throw();

  void terminate();
  void unexpected();

  bool uncaught_exception() throw();

  struct nothrow_t { };
  extern const nothrow_t nothrow;

  // Abstract base type for exceptions with associated error
  // constants from system_error, but no embedded strings.
  struct exception_base
  {
    exception_base() throw() { }

    virtual ~exception_base() throw() = 0;

    virtual const bool
    is_rethrown() const throw() = 0;
  };
} // namespace std

#endif // _EXCEPTION

<stdexception>

#ifndef _STDEXCEPT
#define _STDEXCEPT 1

#include <string>

namespace std
{
  // Abstract base type for exceptions with embedded strings.
  struct exception: virtual public exception_base
  {
    exception(const string& s) throw() : _M_string(s) { }

    virtual ~exception() throw() { }

    virtual const string&
    str() const throw() = 0;

    virtual const bool
    is_rethrown() const throw() { return true; }
    
  private:
    string _M_string;
  };

  // Here we go: all exception classes, in a flat hierarchy.
  struct address_family_not_supported_exception : virtual public exception
  {
    explicit address_family_not_supported_exception(const string& s)
    : exception(s) { }

    virtual ~address_family_not_supported_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct address_in_use_exception : virtual public exception
  {
    explicit address_in_use_exception(const string& s)
    : exception(s) { }

    virtual ~address_in_use_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct address_not_available_exception : virtual public exception
  {
    explicit address_not_available_exception(const string& s)
    : exception(s) { }

    virtual ~address_not_available_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct already_connected_exception : virtual public exception
  {
    explicit already_connected_exception(const string& s)
    : exception(s) { }

    virtual ~already_connected_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct argument_list_too_long_exception : virtual public exception
  {
    explicit argument_list_too_long_exception(const string& s)
    : exception(s) { }

    virtual ~argument_list_too_long_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct argument_out_of_domain_exception : virtual public exception
  {
    explicit argument_out_of_domain_exception(const string& s)
    : exception(s) { }

    virtual ~argument_out_of_domain_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct bad_address_exception : virtual public exception
  {
    explicit bad_address_exception(const string& s)
    : exception(s) { }

    virtual ~bad_address_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct bad_file_descriptor_exception : virtual public exception
  {
    explicit bad_file_descriptor_exception(const string& s)
    : exception(s) { }

    virtual ~bad_file_descriptor_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct bad_message_exception : virtual public exception
  {
    explicit bad_message_exception(const string& s)
    : exception(s) { }

    virtual ~bad_message_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct broken_pipe_exception : virtual public exception
  {
    explicit broken_pipe_exception(const string& s)
    : exception(s) { }

    virtual ~broken_pipe_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct connection_aborted_exception : virtual public exception
  {
    explicit connection_aborted_exception(const string& s)
    : exception(s) { }

    virtual ~connection_aborted_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct connection_refused_exception : virtual public exception
  {
    explicit connection_refused_exception(const string& s)
    : exception(s) { }

    virtual ~connection_refused_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct connection_reset_exception : virtual public exception
  {
    explicit connection_reset_exception(const string& s)
    : exception(s) { }

    virtual ~connection_reset_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct cross_device_link_exception : virtual public exception
  {
    explicit cross_device_link_exception(const string& s)
    : exception(s) { }

    virtual ~cross_device_link_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct destination_address_required_exception : virtual public exception
  {
    explicit destination_address_required_exception(const string& s)
    : exception(s) { }

    virtual ~destination_address_required_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct device_or_resource_busy_exception : virtual public exception
  {
    explicit device_or_resource_busy_exception(const string& s)
    : exception(s) { }

    virtual ~device_or_resource_busy_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct directory_not_empty_exception : virtual public exception
  {
    explicit directory_not_empty_exception(const string& s)
    : exception(s) { }

    virtual ~directory_not_empty_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct executable_format_exception : virtual public exception
  {
    explicit executable_format_exception(const string& s)
    : exception(s) { }

    virtual ~executable_format_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct file_exists_exception : virtual public exception
  {
    explicit file_exists_exception(const string& s)
    : exception(s) { }

    virtual ~file_exists_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct file_too_large_exception : virtual public exception
  {
    explicit file_too_large_exception(const string& s)
    : exception(s) { }

    virtual ~file_too_large_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct filename_too_long_exception : virtual public exception
  {
    explicit filename_too_long_exception(const string& s)
    : exception(s) { }

    virtual ~filename_too_long_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct function_not_supportedexception : virtual public exception
  {
    explicit function_not_supportedexception(const string& s)
    : exception(s) { }

    virtual ~function_not_supportedexception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct host_unreachable_exception : virtual public exception
  {
    explicit host_unreachable_exception(const string& s)
    : exception(s) { }

    virtual ~host_unreachable_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct identifier_removed_exception : virtual public exception
  {
    explicit identifier_removed_exception(const string& s)
    : exception(s) { }

    virtual ~identifier_removed_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct illegal_byte_sequence_exception : virtual public exception
  {
    explicit illegal_byte_sequence_exception(const string& s)
    : exception(s) { }

    virtual ~illegal_byte_sequence_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct inappropriate_io_control_operation_exception 
  : virtual public exception
  {
    explicit inappropriate_io_control_operation_exception(const string& s)
    : exception(s) { }

    virtual ~inappropriate_io_control_operation_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct interrupted_exception : virtual public exception
  {
    explicit interrupted_exception(const string& s)
    : exception(s) { }

    virtual ~interrupted_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct invalid_argument_exception : virtual public exception
  {
    explicit invalid_argument_exception(const string& s)
    : exception(s) { }

    virtual ~invalid_argument_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct invalid_seek_exception : virtual public exception
  {
    explicit invalid_seek_exception(const string& s)
    : exception(s) { }

    virtual ~invalid_seek_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct io_exception : virtual public exception
  {
    explicit io_exception(const string& s)
    : exception(s) { }

    virtual ~io_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct is_a_directory_exception : virtual public exception
  {
    explicit is_a_directory_exception(const string& s)
    : exception(s) { }

    virtual ~is_a_directory_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct message_too_long_exception : virtual public exception
  {
    explicit message_too_long_exception(const string& s)
    : exception(s) { }

    virtual ~message_too_long_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct network_down_exception : virtual public exception
  {
    explicit network_down_exception(const string& s)
    : exception(s) { }

    virtual ~network_down_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct network_reset_exception : virtual public exception
  {
    explicit network_reset_exception(const string& s)
    : exception(s) { }

    virtual ~network_reset_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct network_unreachable_exception : virtual public exception
  {
    explicit network_unreachable_exception(const string& s)
    : exception(s) { }

    virtual ~network_unreachable_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_buffer_space_exception : virtual public exception
  {
    explicit no_buffer_space_exception(const string& s)
    : exception(s) { }

    virtual ~no_buffer_space_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_child_process_exception : virtual public exception
  {
    explicit no_child_process_exception(const string& s)
    : exception(s) { }

    virtual ~no_child_process_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_link_exception : virtual public exception
  {
    explicit no_link_exception(const string& s)
    : exception(s) { }

    virtual ~no_link_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_lock_available_exception : virtual public exception
  {
    explicit no_lock_available_exception(const string& s)
    : exception(s) { }

    virtual ~no_lock_available_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_message_available_exception : virtual public exception
  {
    explicit no_message_available_exception(const string& s)
    : exception(s) { }

    virtual ~no_message_available_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_message_exception : virtual public exception
  {
    explicit no_message_exception(const string& s)
    : exception(s) { }

    virtual ~no_message_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_space_on_device_exception : virtual public exception
  {
    explicit no_space_on_device_exception(const string& s)
    : exception(s) { }

    virtual ~no_space_on_device_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_stream_resources_exception : virtual public exception
  {
    explicit no_stream_resources_exception(const string& s)
    : exception(s) { }

    virtual ~no_stream_resources_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_such_device_or_address_exception : virtual public exception
  {
    explicit no_such_device_or_address_exception(const string& s)
    : exception(s) { }

    virtual ~no_such_device_or_address_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_such_device_exception : virtual public exception
  {
    explicit no_such_device_exception(const string& s)
    : exception(s) { }

    virtual ~no_such_device_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_such_file_or_directory_exception : virtual public exception
  {
    explicit no_such_file_or_directory_exception(const string& s)
    : exception(s) { }

    virtual ~no_such_file_or_directory_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct no_such_process_exception : virtual public exception
  {
    explicit no_such_process_exception(const string& s)
    : exception(s) { }

    virtual ~no_such_process_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct not_a_directory_exception : virtual public exception
  {
  
    explicit not_a_directory_exception(const string& s)
    : exception(s) { }

    virtual ~not_a_directory_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct not_a_socket_exception : virtual public exception
  {
    explicit not_a_socket_exception(const string& s)
    : exception(s) { }

    virtual ~not_a_socket_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct not_a_stream_exception : virtual public exception
  {
    explicit not_a_stream_exception(const string& s)
    : exception(s) { }

    virtual ~not_a_stream_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct not_connected_exception : virtual public exception
  {
    explicit not_connected_exception(const string& s)
    : exception(s) { }

    virtual ~not_connected_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct not_enough_memory_exception : virtual public exception
  {
    explicit not_enough_memory_exception(const string& s)
    : exception(s) { }

    virtual ~not_enough_memory_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct not_supported_exception : virtual public exception
  {
    explicit not_supported_exception(const string& s)
    : exception(s) { }

    virtual ~not_supported_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct operation_canceled_exception : virtual public exception
  {
    explicit operation_canceled_exception(const string& s)
    : exception(s) { }

    virtual ~operation_canceled_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct operation_in_progress_exception : virtual public exception
  {
    explicit operation_in_progress_exception(const string& s)
    : exception(s) { }

    virtual ~operation_in_progress_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct operation_already_in_progress_exception : virtual public exception
  {
    explicit operation_already_in_progress_exception(const string& s)
    : exception(s) { }

    virtual ~operation_already_in_progress_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct operation_no_permitted_exception : virtual public exception
  {
    explicit operation_no_permitted_exception(const string& s)
    : exception(s) { }

    virtual ~operation_no_permitted_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct operation_not_supported_exception : virtual public exception
  {
    explicit operation_not_supported_exception(const string& s)
    : exception(s) { }

    virtual ~operation_not_supported_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct owner_dead_exception : virtual public exception
  {
    explicit owner_dead_exception(const string& s)
    : exception(s) { }

    virtual ~owner_dead_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct permission_denied_exception : virtual public exception
  {
    explicit permission_denied_exception(const string& s)
    : exception(s) { }

    virtual ~permission_denied_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct protocol_exception : virtual public exception
  {
    explicit protocol_exception(const string& s)
    : exception(s) { }

    virtual ~protocol_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct protocol_no_available_exception : virtual public exception
  {
    explicit protocol_no_available_exception(const string& s)
    : exception(s) { }

    virtual ~protocol_no_available_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct protocol_not_supported_exception : virtual public exception
  {
    explicit protocol_not_supported_exception(const string& s)
    : exception(s) { }

    virtual ~protocol_not_supported_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct read_only_file_system_exception : virtual public exception
  {
    explicit read_only_file_system_exception(const string& s)
    : exception(s) { }

    virtual ~read_only_file_system_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct resource_deadlock_would_occur_exception : virtual public exception
  {
    explicit resource_deadlock_would_occur_exception(const string& s)
    : exception(s) { }

    virtual ~resource_deadlock_would_occur_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct result_out_of_range_exception : virtual public exception
  {
    explicit result_out_of_range_exception(const string& s)
    : exception(s) { }

    virtual ~result_out_of_range_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct state_not_recoverable_exception : virtual public exception
  {
    explicit state_not_recoverable_exception(const string& s)
    : exception(s) { }

    virtual ~state_not_recoverable_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct stream_timeout_exception : virtual public exception
  {
    explicit stream_timeout_exception(const string& s)
    : exception(s) { }

    virtual ~stream_timeout_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct text_file_busy_exception : virtual public exception
  {
    explicit text_file_busy_exception(const string& s)
    : exception(s) { }

    virtual ~text_file_busy_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct timed_out_exception : virtual public exception
  {
    explicit timed_out_exception(const string& s)
    : exception(s) { }

    virtual ~timed_out_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct too_many_files_open_in_system_exception : virtual public exception
  {
    explicit too_many_files_open_in_system_exception(const string& s)
    : exception(s) { }

    virtual ~too_many_files_open_in_system_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct too_many_files_open_exception : virtual public exception
  {
    explicit too_many_files_open_exception(const string& s)
    : exception(s) { }

    virtual ~too_many_files_open_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct too_many_links_exception : virtual public exception
  {
    explicit too_many_links_exception(const string& s)
    : exception(s) { }

    virtual ~too_many_links_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct too_many_symbolic_link_levels_exception : virtual public exception
  {
    explicit too_many_symbolic_link_levels_exception(const string& s)
    : exception(s) { }

    virtual ~too_many_symbolic_link_levels_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct try_again_exception : virtual public exception
  {
    explicit try_again_exception(const string& s)
    : exception(s) { }

    virtual ~try_again_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct value_too_large_exception : virtual public exception
  {
    explicit value_too_large_exception(const string& s)
    : exception(s) { }

    virtual ~value_too_large_exception() throw() { }

    virtual const string&
    str() const throw();
  };

  struct wrong_protocol_type_exception : virtual public exception
  {
    explicit wrong_protocol_type_exception(const string& s)
    : exception(s) { }

    virtual ~wrong_protocol_type_exception() throw() { }

    virtual const string&
    str() const throw();
  };
} // namespace std

#endif // _STDEXCEPT

<exception_utils>

#ifndef _EXCEPTION_UTILS
#define _EXCEPTION_UTILS 1

#include <system_error>
#include <stdexcept>

namespace std
{
  template<typename _Exception>
  _Exception
  use_exception(int, std::string& msg);

  // If exceptions, throws via use_exception(value), if not, sets error.
  void 
  raise_error(int& toset, const int value);

  // Never
  void 
  raise_error(int& toset, const int value, const nothrow_t&);
}  // namespace std

#endif // _EXCEPTION_UTILS