polymorphic_allocator: when and why should I use it?

Here is the documentation on cppreference, here is the working draft.

I must admit that I didn't understand what's the real purpose of polymorphic_allocator and when/why/how I should use it.
As an example, the pmr::vector has the following signature:

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

What does the polymorphic_allocator offer? What does the std::pmr::vector offer as well in regard of the old-fashioned std::vector? What can I do now that I wasn't able to do till now?
What's the real purpose of that allocator and when should I use it actually?

32210 次浏览

polymorphic_allocator对自定义分配程序的作用就像 std::function对直接函数调用的作用一样。

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

也许您想隐藏使用哪个分配程序来简化您的接口,或者也许您希望能够将其替换为不同的运行时情况。

首先,您需要一个需要分配器的代码,然后您需要能够交换使用哪个分配器,然后再考虑 pmrVector。

选择引自 cpferences:

这种运行时多态性允许使用多态 _ 分配器的对象在运行时使用不同的分配器类型,尽管它们使用相同的静态分配器类型

“常规”分配器的问题在于它们改变了容器的类型。如果需要具有特定分配器的 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::容器兼容。在设计与容器一起工作的接口时,您需要做出一些决定:

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

模板解决方案允许使用 任何分配器,包括多态分配器,但是也有其他缺点(生成的代码大小、编译时间、代码必须暴露在头文件中,可能导致进一步的“类型污染”,从而使问题向外扩展)。另一方面,多态分配器解决方案要求使用多态分配器 必须的。这就排除了使用使用默认分配器的 std::容器,并且可能会影响与遗留代码的接口。

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

多态分配器的一个缺点是 polymorphic_allocator<T>::pointer始终只是 T*。这意味着你不能使用他们与 好点子。如果您想在共享内存中放置 vector的元素并通过 boost::interprocess::offset_ptr访问它们,那么需要使用一个常规的旧的非多态分配器。

因此,尽管多态分配器允许您改变分配 行为而不改变容器的静态类型,但是它们限制了分配 是。