rieux
rieux

Reputation: 829

What does the std::list do with its allocator argument?

std::list is parameterized by an allocator type, which it presumably rebinds in order to allocate list nodes rather than Ts. So what does it do with the object of allocator type passed to the constructor?

template <class T, class Alloc = std::allocator<T>>
class list
{
    class node { ... T element; ... };

    using real_alloc =
        typename std::allocator_traits<Alloc>::template rebind_alloc<node>;
    real_alloc m_allocator;

public:
    list(const Alloc&);
};

In the above code, we need to initialize m_allocator to a node allocator, but the constructor is given a T allocator. Do we just drop the T allocator on the floor, or do we use it somehow?

Upvotes: 5

Views: 976

Answers (2)

sbabbi
sbabbi

Reputation: 11181

Since C++11 allocators can be stateful. You want to construct your internal allocator using the user supplied one. An Allocator is explicitely required to be constructible from typename std::allocator_traits<Alloc>::template rebind_alloc<U>.

Implementations of list constructor should look like this:

template<class T, class Alloc>
class list
{
      struct node_type {/*etc*/}; //internal
      using allocator_type_internal = typename std::allocator_traits<Alloc>::template rebind_alloc<node_type>;
      // etc.
      allocator_type_internal m_allocator; //Note we use allocator_type, not Alloc.
};

list::list(const Alloc& alloc ) : 
     m_allocator(alloc)
{ /* initialize sentinel node, etc. */ }

Although a good implementation would use empty-base optimization for the allocator.

Upvotes: 4

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153810

The T allocator is still used to construct() and destroy() the T portion of the internal nodes. Using these operations may be necessary to add custom arguments during construction, e.g., optionally forward a suitable allocator argument to the constructed objects.

Upvotes: 2

Related Questions