Exceptions Thrown by STLplus Containers


The STLplus library throws exceptions to indicate that a component has been misused in some way. It never throws an exception during normal operation with the notable special case of the message_handler component which can throw the message_handler_limit_error exception during normal execution - read the documentation for message_handler to find out why and how to deal with it.

All exceptions used by STLplus are subclasses of std::exception, so all exceptions can be handled by simply catching this one superclass. In fact, all exceptions are subclasses of either std::logic_error and std::runtime_error.

Of course, instead of just catching std:exception, you can catch particular exceptions if there is any special handling to be performed on that particular exception.

For example, the following snippet of C++ handles the above-mentioned example of the message_handler's limit_error as a special case and then all other standard exceptions as a general case:

message_handler errors(std::cout, 10, true);
  // use the error handler
catch(message_handler_limit_error& exception)
  // special handling of the error handler's limit_error
catch(std::exception& exception)
  // general handling of std::exception and any of its derivatives
return errors.error_count();

Note that catching an exception by reference preserves the subclass information (see "The C++ Programming Language", Bjarne Stroustrup, ch14) so that dynamic casts could be used on a std::exception to get the subclass information.

In practice, exceptions should only be caught in one or two places in the program - the main task of exceptions is to detect programming errors during software development. The what() method of the exception returns a char* message containing a description of the problem. The STLplus-thrown exceptions always indicate which component threw the exception.

The idea is that you catch the exception - probably only in the main() function of the application - and print out the what() description. This will enable you to get a starting point for looking for the programming error that causes the exception to be thrown. In theory at least, release versions of software should not throw any exceptions (with the above-mentioned message_handler_limit_error being a notable special-case).

The philosophy here is to use C++ standard exceptions where they are appropriate (for example std::out_of_range for an index that's out of range of an array). If there isn't a standard exception that's appropriate, then the exception will be classed as general to the STLplus or specific to a component. General exceptions will be collected into a header exceptions.hpp whilst specific exceptions will be declared in the specific component's header - as is already the case for components like the message_handler and ntree.

The Standard Exceptions

The C++ standard includes a set of predefined exceptions, defined in the header <stdexcept>. The exceptions are all based on the superclass std::exception and form a sub-class hierarchy:

Note: those exceptions marked with a tick can be thrown themselves whereas those exceptions marked with a cross are never thrown themselves, but serve as intermediate classes in the hierarchy. You can catch these intermediate classes in which case you will catch all subclasses of them. For example, catching a runtime_error will catch any of range_error, overflow_error or underflow_error plus any other subclasses that may be defined in the future by either the standards committee or by you. It is good practice to catch the intermediate classes because your code will work correctly if new exceptions are added to the set.

There are two sub-groups of exception: logic_error and runtime_error. These represent two different concepts:

Logic Error
Logic errors represent problems in the internal logic of a program; in theory, these are preventable, and even detectable before the program runs (e.g., violations of class invariants).
Runtime Error
Runtime errors represent problems outside the scope of a program; they cannot be easily predicted and can generally only be caught as the program executes.

STLplus Exceptions

Exceptions used in STLplus that are common to more than one component are collected in header exceptions.hpp.

The following exceptions are defined for indicating errors in the use of STLplus iterators in the container classes (well, those that have iterators) and for indicating errors in smart pointers:

null_dereference : logic_error
This is used to indicate that an iterator or smart pointer which is null has been dereferenced. You should always be sure that iterators and smart pointers are non-null before using the * or -> operators.
end_dereference : logic_error
This is used to indicate that an iterator that is pointing to an end element has been dereferenced. In line with STL conventions, the end iterator points to the element after the last element in a container, so dereferencing such an iterator is illegal (the memory pointed to will be unconstructed).
wrong_object : logic_error
This is used to indicate that an iterator which was created by one container has been used in a different container. For example, if you have two graph objects in your program, create an iterator from one graph and then use it in another, then this will throw the wrong_object exception.
illegal_copy : logic_error
This is used to indicate that an attempt has been made to create a copy of an object that cannot be copied - typically when it is stored in a smart_ptr_nocopy object.