1

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.

  • 1
    An Allocator doesn't have to be DefaultConstructible. You can just = delete the default constructor and require that an existing instance be passed to each container – Caleth Oct 11 '17 at 8:25
  • @Caleth Ok, so if my policy's default constructor is deleted (or private) is there a way the abstract class above which accepts policies and traits as template arguments can still be constructed with the stateful policy as a parent class, while remaining general? I don't have any arguments to pass to my stateful policy constructor directly, but it still has mutable state that needs to be initialized when it's instantiated. – Bitrex Oct 11 '17 at 16:29
  • 1
    Require a tag struct as constructor argument in stateful_policy, e.g. struct initialise_policy {}; and then have Allocator::Allocator(PolicyT && p, TraitsT && t) : PolicyT(p), TraitsT(t) {} or somesuch – Caleth Oct 11 '17 at 16:45
  • Although design-level problems are on topic here, I don't think this question fits that category – we are more about software engineering concepts (see our help center). Your problem is less about general design than about C++ specifics. Therefore, I think it should be asked on Stack Overflow instead. – amon Oct 13 '17 at 10:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.