Reputation: 829
std::list
is parameterized by an allocator type, which it presumably rebinds in order to allocate list nodes rather than T
s. 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
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
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