对多态类型使用分配器的正确方法是什么?

时间:2019-06-17 20:02:11

标签: c++ polymorphism c++17 allocator

我正在向系统中添加自定义内存分配器,并试图通过Allocator概念正确地做到这一点,但是当到达所分配组件的类型时,我遇到了一些不确定性已被删除。

class Pimpl_interface {
public:
  virtual ~Pimpl_interface() {}
  virtual void foo() = 0;
};

template<typename T>
class Pimpl : public Pimpl_interface {
public:
  void foo() override {}
};

template<typename Alloc = std::allocator<void>>
class MyType : public Alloc {
  Pimpl_interface * pimpl_ = nullptr;
public:  
  MyType(const Alloc& alloc) : Alloc(alloc) {}

  ~MyType() {
    if(pimpl_) {
      pimpl_->~Pimpl_interface();
      // What do I put here ?????
    }
  }

  template<typename T>
  void bar() {
    using real_alloc_t = typename Alloc::template rebind<Pimpl<T>>::other;
    real_alloc_t alloc(*static_cast<Alloc*>(this));
    Pimpl<T>* ptr = alloc.allocate(1);
    try {
      pimpl_ = new(&ptr) Pimpl<T>();
    }
    catch(...) {
      alloc.deallocate(ptr, 1);
      throw;
    }
  }
};

乍一看,似乎要做的事情是将Alloc重新绑定到Pimpl_interface,并希望这样做是对的。我知道这可以与std::allocator一起正常工作,但是用户分配器应该支持所有可重新分配的分配器类型吗?

在最坏的情况下,我可以使用类似鸭子类型的malloc/free分配器对象,但如果可以的话,我宁愿尝试并遵循标准库。

1 个答案:

答案 0 :(得分:0)

我觉得有很多事情要做。看起来似乎是事情的核心,您想要安全地使用替代分配器(尤其是在PImpl'd类中)。对我而言,该要求中最小的有用部分是使分配器与std::unique_ptr一起使用。如果我正确遵循,我想您会希望它是std::unique_ptr<T, std::function<void(T*)>>。 同样,看起来std::allocate_shared可能与您想要的足够接近。 https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared

这是您需要的吗?:

template<typename Alloc = std::allocator<void>>
class MyType {
  Alloc alloc_;
  std::shared_ptr<Pimpl_interface> pimpl_ = nullptr;
public:  
  MyType(const Alloc& alloc) : Alloc(alloc) {}

  ~MyType() {} // shared_ptr ftw.

  template<typename T>
  void bar() {
    using real_alloc_t = typename Alloc::template rebind<Pimpl<T>>::other;
    real_alloc_t alloc(alloc_);
    pimpl_ = std::allocate_shared<Pimpl<T>>(alloc);
  }
};

(我放弃了Alloc的继承权,因为这看起来像个骰子。)