Costruire un allocatore stateful usando un'interfaccia

1

Ho la seguente classe astratta che implementa il concetto di "Allocatore", utilizzando le politiche e i tratti per personalizzare il comportamento:

#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));
}

Funziona OK se il mio criterio di allocatore è stateless. Tuttavia se il mio criterio di allocatore ha uno stato interno, non voglio che abbia un costruttore pubblico predefinito, perché ciò significherebbe che potrei creare un'istanza di un contenitore STL senza un'istanza di Allocator e, quando ciò accade, il contenitore chiama il costruttore predefinito dell'Allocator Interfaccia e quindi tenta di fare una copia del nuovo allocatore per consegnarlo al contenitore.

Che è male, perché se il PolicyT Allocatore ha uno stato interno, come ad esempio un blocco di memoria che viene usato come un pool allocato nel suo costruttore tramite "nuovo" il cui puntatore è memorizzato come un campo classe e cancellato nel distruttore, il viene anche chiamato il costruttore di copia predefinito del criterio e, quando il contenitore temporaneo e il contenitore escono dall'ambito, viene visualizzata una doppia eliminazione sullo stesso puntatore.

Essenzialmente mi piacerebbe trovare un modo per mantenere un'interfaccia generale come quella sopra, ma progettare i costruttori delle politiche di allocatore che hanno uno stato mutabile tale da poter creare un'istanza di un contenitore Allocator e STL come:

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);

evitando l'ingenua copia-costruzione della politica e il problema del doppio-libero.

    
posta Bitrex 11.10.2017 - 05:39
fonte

0 risposte

Leggi altre domande sui tag