I have the following abstract class which implements the "Allocator" concept, using policies and traits to customize behavior:
#define FORWARD_ALLOCATOR_TRAITS(C) \
typedef typename C::value_type value_type; \
typedef typename C::pointer pointer; \
typedef typename C::const_pointer const_pointer; \
typedef typename C::reference reference; \
typedef typename C::const_reference const_reference; \
typedef typename C::size_type size_type; \
typedef typename C::difference_type difference_type;
template <typename T, typename PolicyT = std::allocator<T>,
typename TraitsT = object_traits<T>>
class Allocator : public PolicyT, public TraitsT {
public:
// Template parameters
typedef PolicyT Policy;
typedef TraitsT Traits;
FORWARD_ALLOCATOR_TRAITS(Policy)
template <typename U>
struct rebind {
typedef Allocator<U, typename Policy::template rebind<U>::other,
typename Traits::template rebind<U>::other> other;
};
Allocator() = default;
template <typename U, typename PolicyU, typename TraitsU>
explicit Allocator(const Allocator<U, PolicyU, TraitsU>& other)
: Policy(other), Traits(other) {}
~Allocator() = default;
};
template <typename T, typename PolicyT, typename TraitsT>
constexpr size_t max_size() {
return PolicyT::max_size();
}
// determines if memory from another
// allocator can be deallocated from this one
template <typename T, typename P, typename Tr>
inline bool operator==(Allocator<T, P, Tr> const& lhs,
Allocator<T, P, Tr> const& rhs) {
return operator==(static_cast<P&>(lhs), static_cast<P&>(rhs));
}
This works OK if my allocator policy is stateless. However if my allocator policy has internal state, I don't want it to have a public default constructor, because that would mean I could instantiate a STL container without an Allocator instance, and when that happens the container calls the default constructor of the Allocator interface and then attempts to make a copy of the newly-created allocator to hand off to the container.
Which is bad, because if the allocator PolicyT has internal state, like say a block of memory that's used as a pool allocated in its constructor via "new" whose pointer is stored as a class field and deleted in the destructor, the default copy constructor of the policy is called as well, and when both the temporary and the container go out of scope you get a double-delete on the same pointer.
Essentially I'd like to find a way to maintain a general interface like the above, but design the constructors of allocator policies which have mutable state such that I can create an instance of an Allocator and STL container like:
template <typename T>
using RebindAlloc =
typename std::allocator_traits <
Allocator<T, MyStatefulAllocator<T>>::template rebind_alloc<T>;
// create allocator instance
auto vector_allocator = RebindAlloc<double>;
// pass allocator instance to vector constructor
auto allocated_vector =
std::vector<double, RebindAlloc<double>>(vector_allocator);
avoiding naive copy-construction of the policy and the double-free problem.
Allocatordoesn't have to beDefaultConstructible. You can just= deletethe default constructor and require that an existing instance be passed to each containerstateful_policy, e.g.struct initialise_policy {};and then haveAllocator::Allocator(PolicyT && p, TraitsT && t) : PolicyT(p), TraitsT(t) {}or somesuch