polymorphic_allocator:何时以及为什么要使用它?

时间:2016-06-24 09:54:23

标签: c++ allocator c++17

Here是关于 cppreference 的文档,here是工作草案。

我必须承认,我并不了解polymorphic_allocator的真正目的是什么以及何时/为何/如何使用它。
例如,pmr::vector具有以下签名:

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

polymorphic_allocator提供什么? std::pmr::vector对于老式的std::vector提供了什么? 我现在能做什么才能做到现在为止? 那个分配器的真正目的是什么?我应该在什么时候使用它呢?

3 个答案:

答案 0 :(得分:61)

来自cppreference的选择引用:

  

此运行时多态性允许使用polymorphic_allocator的对象在运行时使用不同的分配器类型,尽管具有相同的静态分配器类型

&#34;常规&#34;的问题分配器是他们改变容器的类型。如果您希望vector具有特定分配器,则可以使用Allocator模板参数:

auto my_vector = std::vector<int,my_allocator>();

现在的问题是这个向量与具有不同分配器的向量的类型不同。例如,您无法将其传递给需要默认分配器向量的函数,或者将具有不同分配器类型的两个向量分配给同一个变量/指针,例如:

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

多态分配器是单个分配器类型,其成员可以通过动态分派而不是通过模板机制来定义分配器行为。这允许您拥有使用特定的自定义分配但仍然是常见类型的容器。

通过为分配器提供std::memory_resource *

来完成分配器行为的自定义
// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

正如我所看到的,主要的剩余问题是std::pmr::容器仍然与使用默认分配器的等效std::容器不兼容。在设计适用于容器的界面时,您需要做出一些决定:

  • 传入的容器可能需要自定义分配吗?
  • 如果是这样,我应该添加一个模板参数(允许任意分配器)还是应该强制使用多态分配器?

模板解决方案允许任何分配器,包括多态分配器,但还有其他缺点(生成的代码大小,编译时间,代码必须在头文件中公开,有可能进一步&#34;类型污染&#34;它不断向外推动问题)。另一方面,多态分配器解决方案规定必须使用多态分配器。这排除了使用使用默认分配器的std::容器,并且可能会影响与旧代码的接口。

与常规分配器相比,多态分配器确实有一些较小的成本,例如memory_resource指针的存储开销(很可能忽略不计)和分配的虚拟函数调度的成本。实际上,主要问题可能是缺乏与不使用多态分配器的遗留代码的兼容性。

答案 1 :(得分:21)

polymorphic_allocator是自定义分配器,因为std::function是直接函数调用。

它只是让你在容器中使用一个分配器,而不必在声明时决定哪一个。因此,如果您有一个适合多个分配器的情况,您可以使用polymorphic_allocator

也许您想要隐藏哪个分配器用于简化您的界面,或者您希望能够将其交换出来用于不同的运行时案例。

首先,您需要需要分配器的代码,然后在考虑pmr向量之前,您需要能够交换使用哪个代码。

答案 2 :(得分:0)

多态分配器的一个缺点是FROM python:3.6-alpine RUN apk add g++ RUN pip install numpy 始终只是python:3.6。这意味着您不能将它们与fancy pointers一起使用。如果您想做诸如将polymorphic_allocator<T>::pointer的元素放置在共享内存中并通过boost::interprocess::offset_ptrs访问它们的操作,则需要为此使用常规的旧的非多态分配器。

因此,尽管多态分配器使您可以更改分配行为而无需更改容器的静态类型,但它们会限制分配是什么。