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


122

是有关cppreference的文档,是工作草案。

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

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

什么是polymorphic_allocator要约?std::pmr::vector老式的报价又是什么std::vector?到现在为止我还不能做什么?
该分配器的真正目的是什么,我什么时候应该实际使用它?


1
他们试图克服allocator<T>固有的一些问题 。因此,如果经常使用分配器,您将看到其中的价值。
edmz

2
相关文件
edmz

Answers:


103

cppreference中的选择报价:

这种运行时多态性使使用polymorphic_allocator的对象的行为就像在运行时使用了不同的分配器类型一样,尽管静态分配器类型相同

“常规”分配器的问题在于它们会更​​改容器的类型。如果你想要一个vector使用特定的分配器,则可以使用Allocatortemplate参数:

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

多态分配器是具有成员的单个分配器类型,该成员可以通过动态分配而不是通过模板机制来定义分配器行为。这使您可以拥有使用特定的,自定义分配的容器,但是它们仍然是普通类型的。

分配器行为的自定义是通过给分配器a来完成的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指针的存储开销(很可能可以忽略不计)以及为分配分配虚拟函数的开销。实际上,主要问题可能是与不使用多态分配器的旧代码缺乏兼容性。


2
那么,std::pmr::类的二进制布局很可能会有所不同吗?
Euri Pinhollow '17

12
@EuriPinhollow 如果要问的话,您不能reinterpret_caststd::vector<X>和之间std::pmr::vector<X>
davmac

4
对于内存资源不依赖于运行时变量的简单情况,一个好的编译器将进行虚拟化处理,并且最终您将获得一个多态的分配器,而不会产生额外的开销(除了存储指针,这实际上不是问题)。我认为值得一提。
DeiDei

1
@ Yakk-AdamNevraumont std::pmr::容器仍与std::使用默认分配器的等效容器不兼容”。两者之间都没有定义赋值运算符。如有疑问,请尝试:godbolt.org/z/Q5BKev(代码与上面的代码不完全相同,因为gcc / clang在“实验”名称空间中具有多态分配类)。
davmac

1
@davmac啊,所以没有template<class OtherA, std::enable_if< A can be constructed from OtherA > vector( vector<T, OtherA>&& )构造函数。我不确定,也不知道在哪里可以找到符合TS的pmr的编译器。
Yakk-Adam Nevraumont

33

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

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

也许您想隐藏使用哪个分配器来简化您的接口,或者也许希望能够将其分配给不同的运行时实例。

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


7

多态分配器的一个缺点polymorphic_allocator<T>::pointer是总是正义T*。这意味着您不能将它们与精美的指针一起使用。如果要执行诸如将a的元素放置vector在共享内存中并通过boost::interprocess::offset_ptrs访问它们的操作,则需要为此使用常规的旧的非多态分配器。

因此,尽管多态分配器使您可以在不更改容器静态类型的情况下更改分配行为,但它们会限制分配的内容。


2
这是一个关键点,也是一个大麻烦。亚瑟·奥德威尔(Arthur O'Dwyer)的《走向有意义的花式指针》论文探索了这一领域,他的书《精通c ++ 17 STL》也是如此
6

您能否给出使用多态分配器的实际用例?
darune
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.