# Boost.MultiIndex Tutorial: Debugging support

Container creation
Boost.MultiIndex tutorial
Techniques

## Contents

- Debugging support
- Safe mode
  - Serialization and safe mode
- Invariant-checking mode

## Debugging support

The concept of Design by Contract, originally developed as part of Bertrand Meyer's Eiffel language, revolves around the formulation of a contract between the user of a library and the implementor, by which the first is required to respect some preconditions on the values passed when invoking methods of the library, and the implementor guarantees in return that certain constraints on the results are met (postconditions), as well as the honoring of specified internal consistency rules, called invariants. Eiffel natively supports the three parts of the contract just described by means of constructs `require`, `ensure` and `invariant`, respectively.

C++ does not enjoy direct support for Design by Contract techniques: these are customarily implemented as assertion code, often turned off in release mode for performance reasons. Following this approach, Boost.MultiIndex provides two distinct debugging modes:

- Safe mode checks preconditions on the invocations to the facilities of the library,
- invariant-checking mode performs post-execution checks aimed at ensuring that the internal consistency of the library is preserved.

These two modes are independent of each other and can be set on or off individually. It is important to note that errors detected by safe mode are due in principle to faulty code in the user's program, while invariant-checking mode detects potential internal bugs in the implementation of Boost.MultiIndex.

## Safe mode

The idea of adding precondition checking facilities to STL as a debugging aid was first introduced by Cay S. Horstmann in his Safe STL library and later adopted by STLport Debug Mode. Similarly, Boost.MultiIndex features the so-called safe mode in which all sorts of preconditions are checked when dealing with iterators and functions of the library.

Boost.MultiIndex safe mode is set by globally defining the macro `BOOST_MULTI_INDEX_ENABLE_SAFE_MODE`. Error conditions are checked via the macro `BOOST_MULTI_INDEX_SAFE_MODE_ASSERT`, which by default resolves to a call to `BOOST_ASSERT`.

If the user decides to define her own version of `BOOST_MULTI_INDEX_SAFE_MODE_ASSERT`, it has to take the form

>     BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code)

where `expr` is the condition checked and `error_code` is one value of the `safe_mode::error_code` enumeration:

>     namespace boost{

>     namespace multi_index{

>     namespace safe_mode{

>     enum error_code
>     {
>       invalid_iterator,             // vg. default cted or pointing to erased element
>       not_dereferenceable_iterator, // iterator is not dereferenceable
>       not_incrementable_iterator,   // iterator points to end of sequence
>       not_decrementable_iterator,   // iterator points to beginning of sequence
>       not_owner,                    // iterator does not belong to the container
>       not_same_owner,               // iterators belong to different containers
>       invalid_range,                // last not reachable from first
>       inside_range,                 // iterator lies within a range (and it mustn't)
>       out_of_bounds,                // move attempted beyond container limits
>       same_container,               // containers ought to be different
>       unequal_allocators            // allocators ought to be equal
>     };

>     } // namespace multi_index::safe_mode

>     } // namespace multi_index

>     } // namespace boost

For instance, the following replacement of `BOOST_MULTI_INDEX_SAFE_MODE_ASSERT` throws an exception instead of asserting:

>     #include <boost/multi_index_container/safe_mode_errors.hpp>

>     struct safe_mode_exception
>     {
>       safe_mode_exception(boost::multi_index::safe_mode::error_code error_code):
>         error_code(error_code)
>       {}

>       boost::multi_index::safe_mode::error_code error_code;
>     };

>     #define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) \
>     if(!(expr)){throw safe_mode_exception(error_code);}

>     // This has to go before the inclusion of any header from Boost.MultiIndex,
>     // except possibly safe_error_codes.hpp.

Other possibilites, like outputting to a log or firing some kind of alert, are also implementable.

Warning: Safe mode adds a very important overhead to the program both in terms of space and time used, so in general it should not be set for `NDEBUG` builds. Also, this mode is intended solely as a debugging aid, and programs must not rely on it as part of their normal execution flow: in particular, no guarantee is made that all possible precondition errors are diagnosed, or that the checks remain stable across different versions of the library.

### Serialization and safe mode

Iterators restored from an archive are not subject to safe mode checks. This is so because it is not possible to automatically know the associated `multi_index_container` of an iterator from the serialization information alone. However, if desired, a restored iterator can be converted to a checked value by using the following workaround:

>     employee_set es;
>     employee_set::nth_index<1>::iterator it;

>     // restore es and it from an archive ar
>     ar>>es;
>     ar>>it; // it won't benefit from safe mode checks

>     // Turn it into a checked value by providing Boost.MultiIndex
>     // with info about the associated container.
>     // This statement has virtually zero cost if safe mode is turned off.
>     it=es.project<1>(it);

## Invariant-checking mode

The so called invariant-checking mode of Boost.MultiIndex can be set by globally defining the macro `BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING`. When this mode is in effect, all public functions of Boost.MultiIndex will perform post-execution tests aimed at ensuring that the basic internal invariants of the data structures managed are preserved.

If an invariant test fails, Boost.MultiIndex will indicate the failure by means of the unary macro `BOOST_MULTI_INDEX_INVARIANT_ASSERT`. Unless the user provides a definition for this macro, it defaults to `BOOST_ASSERT`. Any assertion of this kind should be regarded in principle as a bug in the library. Please report such problems, along with as much contextual information as possible, to the maintainer of the library.

It is recommended that users of Boost.MultiIndex always set the invariant-checking mode in debug builds.

Container creation
Boost.MultiIndex tutorial
Techniques

Revised May 9th 2020

© Copyright 2003-2020 Joaquín M López Muñoz. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)