The libcult exception handling library defines a base exception type to be used by the rest of libcult. It has a very basic interface:

namespace Cult
{
  namespace EH
  {
    class Exception: public virtual std::exception
    {
    public:
      virtual char const*
      what () const throw ();
    };
  }
}

It derives from std::exception to allow catching all exceptions with a single handler. Default implementation of the what() member function returns type-name of the exception.

Every non-trivial library in libcult derives its own base exception which all library-defined exceptions inherit. This way you can catch all exceptions from a library with one handler.

Sometimes it may seem convenient to further partition (by providing corresponding base classes) exceptions space into logic exceptions (shared by all implementations) and implementation exceptions. For example, if you pass an allocator illegal size 0 then the allocator throws an exception which can be classified as a logic exception. If, however, you passed valid size but there is not enough memory then the allocator throws an exception which can be classified as an implementation exception1.

The problem with this approach lies in the fact that someone's logic exception is someone else's implementation exception. Consider, for instance, a buffer type that is implemented in terms of our allocator. If the buffer happened to request a memory block of size 0 and let the exception propagate through the interface boundaries it is no longer a logic exception.


1 It can be argued that the NoMemory exception should rather be classified as logic. However, let's assume there are allocator implementations that have infinite memory.

Copyright © 2005-2010 Boris Kolpackov.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, version 1.2; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.