但是我怎么知道容器使用哪种分配器,如果它
从模板参数内部重新绑定给定的分配器?
始终向构造函数提供Allocator<T>(其中T 是容器的value_type)。容器会将其转换为 Allocator<U> 是必要的,其中 U 是容器的一些内部数据结构。 Allocator 需要提供这样的转换构造函数,例如:
template <class T> class allocator {
...
template <class U> allocator(const allocator<U>&);
此外,我读到 C++11 现在使用范围分配器,它允许
将容器的分配器重用于其包含的容器。
嗯,更准确地说,C++11 有一个名为scoped_allocator_adaptor 的分配器适配器:
template <class OuterAlloc, class... InnerAllocs>
class scoped_allocator_adaptor : public OuterAlloc
{
...
};
来自 C++11:
类模板scoped_allocator_adaptor是一个分配器模板
指定要使用的内存资源(外部分配器)
一个容器(就像任何其他分配器一样)并且还指定了一个内部
要传递给每个元素的构造函数的分配器资源
容器内。这个适配器是用一个外部实例化的,并且
零个或多个内部分配器类型。如果只用一个实例化
分配器类型,内部分配器成为
scoped_allocator_adaptor 本身,因此使用相同的分配器
容器和容器内每个元素的资源,以及
如果元素本身是容器,则它们的每个元素
递归地。如果用多个分配器实例化,则第一个
allocator 是容器使用的外部分配器,第二个
分配器被传递给容器元素的构造函数,
并且,如果元素本身是容器,则第三个分配器是
传递给元素的元素,依此类推。如果容器是嵌套的
深度大于分配器的数量,最后一个分配器
重复使用,如在单分配器的情况下,对于任何剩余的
递归。 [注意:scoped_allocator_adaptor 源自
外部分配器类型,因此可以替换外部分配器
输入大多数表达式。 — 尾注 ]
因此,如果您将 scoped_allocator_adaptor 指定为容器的分配器,您只会获得作用域分配器行为。
如何实现一个作用域分配器启用容器
与不知道作用域容器的大致不同?
关键是容器现在通过一个名为allocator_traits 的新类来处理它的分配器,而不是直接处理分配器。并且容器必须使用allocator_traits进行某些操作,例如在容器中构造和销毁value_types。容器不得直接与分配器对话。
例如,分配器可以提供一个名为construct的成员,它将使用给定的参数在某个地址构造一个类型:
template <class T> class Allocator {
...
template<class U, class... Args>
void construct(U* p, Args&&... args);
};
如果分配器不提供此成员,allocator_traits 将提供默认实现。无论如何,容器必须使用这个construct函数构造所有value_types,但是通过allocator_traits使用它,而不是直接使用allocator:
allocator_traits<allocator_type>::construct(the_allocator, *ugly details*);
scoped_allocator_adaptor 提供了自定义的construct 函数,allocator_traits 将利用uses_allocator 特征将正确的分配器传递给value_type 构造函数。容器仍然对这些细节一无所知。容器只需要知道它必须使用allocator_traits construct函数构造value_type。
容器必须处理更多细节才能正确处理有状态分配器。虽然这些细节也是通过让容器不做任何假设而是通过allocator_traits 获取所有属性和行为来处理的。容器甚至不能假设pointer 是T*。而是通过询问 allocator_traits 它是什么来找到这种类型。
简而言之,要构建 C++11 容器,请在 allocator_traits 上学习。然后,当您的客户使用 scoped_allocator_adaptor 时,您可以免费获得作用域分配器行为。