Exceptions Thrown by STLplus

Philosophy

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 error_handler component which can throw the error_handler_limit_error exception during normal execution - read the documentation for error_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 error_handler's limit_error as a special case and then all other standard exceptions as a general case:

error_handler errors(fout, 10, true);
try
{
  // use the error handler
}
catch(error_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 derivative information (see "The C++ Programming Language", Bjarne Stroustrup, ch14) so that dynamic casts could be used on a std::exception to get the derivative 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 error_handler_limit_error being a notable special-case).

The conversion of the STLplus library to use exceptions is an ongoing project.

The long-term plan is to gradually convert all STLplus components to use exceptions for error handling. 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 error_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:

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 three 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.

Status

The STLplus library is currently only partly converted to use exceptions. Some of the older components do not use them. Instead, some components use assertions to indicate a misuse of the component.

As an interim measure, the assertion used throughout the STLplus library is the DEBUG_ASSERT macro defined in debug.hpp. This macro calls a function that throws an exception to indicate the assertion failure. This exception - assert_failed - is a subclass of std::logic_error. Therefore, assertion failures are handled by any catch block that handles these standard exceptions.