【问题标题】:Custom allocator for nested containers嵌套容器的自定义分配器
【发布时间】:2021-02-16 16:16:38
【问题描述】:

我正在研究自定义分配器。到目前为止,我已经尝试过处理简单的容器:std::list、std::vector、std::basic_string 等......

我的自定义分配器是一个静态缓冲区分配器,它的实现很简单:

#include <memory>

template <typename T>
class StaticBufferAlloc : std::allocator<T>
{
private:
    T *memory_ptr;
    std::size_t memory_size;

public:
    typedef std::size_t size_type;
    typedef T *pointer;
    typedef T value_type;

    StaticBufferAlloc(T *memory_ptr, size_type memory_size) : memory_ptr(memory_ptr), memory_size(memory_size) {}
    StaticBufferAlloc(const StaticBufferAlloc &other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size){};
    pointer allocate(size_type n, const void *hint = 0) { return memory_ptr; } // when allocate return the buffer
    void deallocate(T *ptr, size_type n) {}                                    // empty cause the deallocation is buffer creator's responsability

    size_type max_size() const { return memory_size; }
};

我以这种方式使用它:

  using inner = std::vector<int, StaticBufferAlloc<int>>;
  int buffer[201];
  auto alloc1 = StaticBufferAlloc<int>(&buffer[100], 50);
  inner v1(0, alloc1);
  assert(v1.size() == 0);
  const int N = 10; 
  // insert 10 integers
  for (size_t i = 0; i < N; i++)  {
    v1.push_back(i);
  }
  assert(v1.size() == N);

到目前为止一切都很好,当我将 N 增加到超过它抛出的最大缓冲区大小时,这是预期的。


现在,我正在尝试使用嵌套容器。简而言之,我试图拥有一个向量(矩阵)的向量,其中父向量及其所有底层元素(即向量即容器)共享相同的静态缓冲区以进行分配。看起来scoped_allocator 可以解决我的问题。

  using inner = std::vector<int, StaticBufferAlloc<int>>;
  using outer = std::vector<inner, std::scoped_allocator_adaptor<StaticBufferAlloc<inner>>>;

  int buffer[201];
  auto alloc1 = StaticBufferAlloc<int>(&buffer[100], 50);
  auto alloc2 = StaticBufferAlloc<int>(&buffer[150], 50);
  inner v1(0, alloc1);
  inner v2(0, alloc2);
  assert(v1.size() == 0);
  assert(v2.size() == 0);

  const int N = 10; 
  // insert 10 integers
  for (size_t i = 0; i < N; i++)
  {
    v1.push_back(i);
    v2.push_back(i);
  }
  assert(v1.size() == N);
  assert(v2.size() == N);

  outer v // <- how to construct this vector with the outer buffer? 
  v.push_back(v1);
  v.push_back(v2); 
  ...

我的问题是如何在其构造函数调用中使用其静态缓冲区初始化外部向量?

【问题讨论】:

    标签: c++ memory-management allocator


    【解决方案1】:

    在 C++11/C++14 中创建一个作用域分配器有点挑战性。所以我选择了一个在 C++17 中引入的非常现代的解决方案。我没有实现分配器,而是使用了polymorphic_allocator。多态分配器是作用域分配器,标准容器会自动将分配器传递给子对象。

    基本上,这个想法是使用多态分配器并将monotonic_buffer_resource 注入它。 monotonic_buffer_resource 可以用memory resource 初始化。

    编写自定义内存资源非常简单:

    class custom_resource : public std::pmr::memory_resource
    {
    public:
      explicit custom_resource(std::pmr::memory_resource *up = std::pmr::get_default_resource())
          : _upstream{up}
      {
      }
    
      void *do_allocate(size_t bytes, size_t alignment) override
      {
        return _upstream; //do nothing, don't grow just return ptr
      }
    
      void do_deallocate(void *ptr, size_t bytes, size_t alignment) override
      {
        //do nothing, don't deallocate
      }
    
      bool do_is_equal(const std::pmr::memory_resource &other) const noexcept override
      {
        return this == &other;
      }
    
    private:
      std::pmr::memory_resource *_upstream;
    };
    

    使用起来更简单:

     std::byte buffer[512];
     custom_resource resource;
     std::pmr::monotonic_buffer_resource pool{std::data(buffer), std::size(buffer), &resource};
     std::pmr::vector<std::pmr::vector<int>> outer(&pool)
    

    请务必注意,std::pmr::vector&lt;T&gt; 只是 std::vector&lt;T, polymorphic_allocator&gt;

    有用的资源:


    std::pmr 很酷,但它需要现代版本的 gcc 才能运行 (9+)。幸运的是,Reddit 上到处都是善良的陌生人。可以在here找到一个 C++14 的解决方案。

    【讨论】:

      猜你喜欢
      • 2011-03-17
      • 2022-01-08
      • 1970-01-01
      • 2017-12-04
      • 2012-09-23
      • 2015-07-05
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多