【问题标题】:Stateful custom deleter for unique_ptrunique_ptr 的有状态自定义删除器
【发布时间】:2019-08-23 08:32:29
【问题描述】:

我正在使用内存池来加快分配和释放速度。内存池的Release()操作需要释放指针和分配的字节数。

现在我想将从内存池中获得的数组指针存储在unique_ptr 中。数组的大小是可变的,所以我需要一个有状态的自定义删除器来存储数组的大小。

您能否提供有关如何声明此类unique_ptr 的示例代码?

更新:在 Artyer 的提示让我明白之后,这是我尝试过的:

template<typename T> struct MPSingleDeleter {
  void operator()(T *p) {
    p->~T();
    MemPool::Instance().Release(p, sizeof(T));
  }
};

template<typename T> struct MPArrayDeleter {
  size_t _nItems;

  explicit MPArrayDeleter(const size_t nItems) : _nItems(nItems) {
  }

  void operator()(T *p) {
    for (size_t i = 0; i < _nItems; i++) {
      p[i].~T();
    }
    MemPool::Instance().Release(p, _nItems * sizeof(T));
  }
};

template <typename T> using SingleUP = std::unique_ptr<T, MPSingleDeleter<T>>;
template <typename T> using ArrayUP = std::unique_ptr<T[], MPArrayDeleter<T>>;

struct MemHelper {
  template<typename T, typename ...Args>  static T* NewSingle(Args&&... args) {
    void * const p = MemPool::Instance().Acquire(sizeof(T));
    ::new (p) T(std::forward<Args>(args)...);
    return static_cast<T*>(p);
  }

  template<typename T, typename ...Args> static T* NewArray(const size_t nItems, Args&&... args) {
    T *p = static_cast<T*>(MemPool::Instance().Acquire(nItems * sizeof(T)));
    for (size_t i = 0; i < nItems; i++) {
      void * const pv = static_cast<void *>(p + i);
      ::new (pv) T(std::forward<Args>(args)...);
    }
    return p;
  }

  template<typename T, typename ...Args> static SingleUP<T> MakeSUP(Args&&... args) {
    return SingleUP<T>(NewSingle<T>(std::forward<Args>(args)...));
  }

  template<typename T, typename ...Args> static ArrayUP<T> MakeAUP(const size_t nItems, Args&&... args) {
    return ArrayUP<T>(NewArray<T>(nItems, std::forward<Args>(args)...), MPArrayDeleter<T>(nItems));
  }
};

现在unique_ptr 变量的声明很简单:

// Array of double
ArrayUP<double> pBuffer = MemHelper::MakeAUP<double>(2ui64 * nItems);
// Single Connection
SingleUP<Connection> pConn = MemHelper::MakeSUP<Connection>(ioContext);

【问题讨论】:

  • 你试过什么? std::unique_ptr模板界面有什么特别不清楚的地方吗?
  • @MaxLanghof,两者都很难提供。很难解释文档中不清楚的地方,而且我的代码库太大而无法在此处发布,而提取一个最小示例则需要解决依赖关系。但我会在 Artyer 的提示后发布我的内容。

标签: c++ memory c++17 smart-pointers


【解决方案1】:

您通常会在分配数据之前将大小存储在内存池中,因此您只需传递一个从指针获取大小的无状态删除器。

您可以轻松地执行以下操作:

#include <memory>

struct pool_deleter {
    std::size_t size;

    template<class T>
    void operator()(T* ptr) noexcept {
        std::destroy_n(ptr, size);
        Release(ptr, size * sizeof(T));
    }
};

template<class T>
using pool_ptr = std::unique_ptr<T, pool_deleter>;

// Used like:
std::size_t n = /* ... */;
T* ptr_ = /* Allocate and construct n objects from pool  */;
pool_ptr<T> ptr{ptr_, pool_deleter{n}};  // Pass the custom deleter as an argument

【讨论】:

  • 谢谢!我的数组对于 AVX2 对齐 32 字节,对于 AVX512 对齐 64 字节,因此将大小作为第一项插入会在每次分配中浪费大量内存。但是您使用unique_ptr 的示例帮助我开发了一种方便的方法。
猜你喜欢
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 2019-01-16
  • 2016-11-23
  • 2015-09-11
相关资源
最近更新 更多