|  | Home | Libraries | People | FAQ | More | 
forward_list<T>vector vs. std::vector
      exception guaranteesvector<bool> specializationstd::memsetBoost.Container aims for full C++11 conformance except reasoned deviations, backporting as much as possible for C++03. Obviously, this conformance is a work in progress so this section explains what C++11 features are implemented and which of them have been backported to C++03 compilers.
        For compilers with rvalue references and for those C++03 types that use
        Boost.Move rvalue reference
        emulation Boost.Container supports all C++11
        features related to move semantics: containers are movable, requirements
        for value_type are those
        specified for C++11 containers.
      
        For compilers with variadic templates, Boost.Container
        supports placement insertion (emplace,
        ...) functions from C++11. For those compilers without variadic templates
        support Boost.Container uses the preprocessor
        to create a set of overloads up to a finite number of parameters.
      
C++03 was not stateful-allocator friendly. For compactness of container objects and for simplicity, it did not require containers to support allocators with state: Allocator objects need not be stored in container objects. It was not possible to store an allocator with state, say an allocator that holds a pointer to an arena from which to allocate. C++03 allowed implementors to suppose two allocators of the same type always compare equal (that means that memory allocated by one allocator object could be deallocated by another instance of the same type) and allocators were not swapped when the container was swapped.
        C++11 further improves stateful allocator support through std::allocator_traits.
        std::allocator_traits is the protocol between
        a container and an allocator, and an allocator writer can customize its behaviour
        (should the container propagate it in move constructor, swap, etc.?) following
        allocator_traits requirements.
        Boost.Container not only supports this model
        with C++11 but also backports it to C++03
        via boost::container::allocator_traits
        including some C++17 changes. This class offers some workarounds for C++03
        compilers to achieve the same allocator guarantees as std::allocator_traits.
      
        In [Boost.Container] containers, if possible, a single allocator is hold
        to construct value_types.
        If the container needs an auxiliary allocator (e.g. an array allocator used
        by deque or stable_vector), that allocator is also
        stored in the container and initialized from the user-supplied allocator
        when the container is constructed (i.e. it's not constructed on the fly when
        auxiliary memory is needed).
      
        C++11 improves stateful allocators with the introduction of std::scoped_allocator_adaptor
        class template. scoped_allocator_adaptor
        is instantiated with one outer allocator and zero or more inner allocators.
      
        A scoped allocator is a mechanism to automatically propagate the state of
        the allocator to the subobjects of a container in a controlled way. If instantiated
        with only one allocator type, the inner allocator becomes the scoped_allocator_adaptor itself, thus using
        the same allocator resource for the container and every element within the
        container and, if the elements themselves are containers, each of their elements
        recursively. If instantiated with more than one allocator, the first allocator
        is the outer allocator for use by the container, the second allocator is
        passed to the constructors of the container's elements, and, if the elements
        themselves are containers, the third allocator is passed to the elements'
        elements, and so on.
      
        Boost.Container implements its own scoped_allocator_adaptor
        class and backports this feature also to C++03 compilers.
        Due to C++03 limitations, in those compilers the allocator propagation implemented
        by scoped_allocator_adaptor::construct
        functions will be based on traits (constructible_with_allocator_suffix
        and constructible_with_allocator_prefix)
        proposed in N2554:
        The Scoped Allocator Model (Rev 2) proposal. In conforming C++11
        compilers or compilers supporting SFINAE expressions (when BOOST_NO_SFINAE_EXPR is NOT defined), traits
        are ignored and C++11 rules (is_constructible<T,
        Args...,
        inner_allocator_type>::value and is_constructible<T,
        allocator_arg_t,
        inner_allocator_type,
        Args...>::value) will be used to detect if the allocator
        must be propagated with suffix or prefix allocator arguments.
      
LWG Issue #233 corrected a defect in C++98 and specified how equivalent keys were to be inserted in associative containers. Boost.Container implements the C++11 changes that were specified in N1780 Comments on LWG issue 233: Insertion hints in associative containers:
a_eq.insert(t):
            If a range containing elements equivalent to t exists in a_eq, t is inserted
            at the end of that range.
          a_eq.insert(p,t):
            t is inserted as close as possible to the position just prior to p.
          Boost.Container supports initialization, assignments and insertions from initializer lists in compilers that implement this feature.
Boost.Container implements C++14 Null Forward Iterators, which means that value-initialized iterators may be compared and compare equal to other value-initialized iterators of the same type. Value initialized iterators behave as if they refer past the end of the same empty sequence (example taken from N3644):
vector<int> v = { ... }; auto ni = vector<int>::iterator(); auto nd = vector<double>::iterator(); ni == ni; // True. nd != nd; // False. v.begin() == ni; // ??? (likely false in practice). v.end() == ni; // ??? (likely false in practice). ni == nd; // Won't compile.
        Boost.Container does not offer C++11 forward_list container yet, but it will
        be available in future versions.
      
        vector does not support
        the strong exception guarantees given by std::vector
        in functions like insert,
        push_back, emplace, emplace_back,
        resize, reserve
        or shrink_to_fit for either
        copyable or no-throw moveable classes. In C++11 move_if_noexcept
        is used to maintain C++03 exception safety guarantees combined with C++11
        move semantics. This strong exception guarantee degrades the insertion performance
        of copyable and throwing-moveable types, degrading moves to copies when such
        types are inserted in the vector using the aforementioned members.
      
        This strong exception guarantee also precludes the possibility of using some
        type of in-place reallocations that can further improve the insertion performance
        of vector See Extended
        Allocators to know more about these optimizations.
      
        vector always uses
        move constructors/assignments to rearrange elements in the vector and uses
        memory expansion mechanisms if the allocator supports them, while offering
        only basic safety guarantees. It trades off exception guarantees for an improved
        performance.
      
Several container operations use a parameter taken by const reference that can be changed during execution of the function. LWG Issue 526 (Is it undefined if a function in the standard changes in parameters?) discusses them:
//Given std::vector<int> v v.insert(v.begin(), v[2]); //v[2] can be changed by moving elements of vector //Given std::list<int> l: l.remove(*l.begin()) //The operation could delete the first element, and then continue trying to access it.
The adopted resolution, NAD (Not A Defect), implies that previous operations must be well-defined. This requires code to detect a reference to an inserted element and an additional copy in that case, impacting performance even when references to already inserted objects are not used. Note that equivalent functions taking rvalue references or iterator ranges require elements not already inserted in the container.
Boost.Container prioritizes performance and has not implemented the NAD resolution: in functions that might modify the argument, the library requires references to elements not stored in the container. Using references to inserted elements yields to undefined behaviour (although in debug mode, this precondition violation could be notified via BOOST_ASSERT).
        vector<bool> specialization
        has been quite problematic, and there have been several unsuccessful tries
        to deprecate or remove it from the standard. Boost.Container
        does not implement it as there is a superior Boost.DynamicBitset
        solution. For issues with vector<bool>
        see the following papers:
      
Quotes:
vector<bool> is not a container and vector<bool>::iterator is not a random-access iterator
            (or even a forward or bidirectional iterator either, for that matter).
            This has already broken user code in the field in mysterious ways.”
          vector<bool> forces a specific (and potentially
            bad) optimization choice on all users by enshrining it in the standard.
            The optimization is premature; different users have different requirements.
            This too has already hurt users who have been forced to implement workarounds
            to disable the 'optimization' (e.g., by using a vector<char> and
            manually casting to/from bool).”
          
        So boost::container::vector<bool>::iterator returns real bool
        references and works as a fully compliant container. If you need a memory
        optimized version of boost::container::vector<bool>,
        please use Boost.DynamicBitset.
      
        Boost.Container uses std::memset
        with a zero value to initialize some types as in most platforms this initialization
        yields to the desired value initialization with improved performance.
      
        Following the C11 standard, Boost.Container
        assumes that for any integer type, the object representation where
        all the bits are zero shall be a representation of the value zero in that
        type. Since _Bool/wchar_t/char16_t/char32_t are also integer types in C, it considers
        all C++ integral types as initializable via std::memset.
      
        By default, Boost.Container also considers
        floating point types to be initializable using std::memset.
        Most platforms are compatible with this initialization, but in case this
        initialization is not desirable the user can #define
        BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_NOT_ZERO
        before including library headers.
      
        By default, it also considers pointer types (pointer and pointer to function
        types, excluding member object and member function pointers) to be initializable
        using std::memset. Most platforms are compatible with
        this initialization, but in case this initialization is not desired the user
        can #define BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO
        before including library headers.
      
        If neither BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_NOT_ZERO
        nor BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO
        is defined Boost.Container also considers
        POD types to be value initializable via std::memset
        with value zero.