STL allocator_traits 中静态成员函数的用途是什么?

What is the purpose of the static member functions in STL's allocator_traits?

我正在尝试实现一个 STL 风格的容器 class,我对 class 中分配器的使用有疑问:

STL allocator_traits 中静态成员函数的用途是什么?

直到现在,我认为我应该实例化 allocator_type(可能通过某种空基优化来改善内存占用)。因此,我最终会得到这样的结果:

struct EmptyBaseOpt : allocator_type
{
  EmptyBaseOpt(const allocator_type & a, allocator_type::const_pointer p)
  : allocator_type(a), prefix_ptr(p) { }

  allocator_type::pointer prefix_ptr;
}

EmptyBaseOpt ebo;

然后,我可以按以下方式使用分配器:

allocator_type & alloc = ebo;
alloc.allocate(100, ebo.prefix_ptr);

另一方面,C++11 中的 allocator_traits 似乎暗示了以下用法:

std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);

我想这个静态 allocate 成员函数可能会通过其默认构造函数创建 allocator_type 的临时临时实例。但这会导致以下问题:

  1. 如果 allocator_type 是有状态分配器会怎样?如果我在 allocator_traits 中使用静态成员函数而不是从 allocator_type 的实例调用非静态方法,这样的分配器是否能够保持它们的状态?

  2. 如果我可以直接使用 allocator_traits 中的静态成员函数,我为什么要实例化 allocator_type 并为 EBO 之类的东西烦恼?

  3. 如前所述,我的理解是任何类似于 class 的模板参数都应在我的容器 class 中实例化,以便允许这些参数的有状态版本。这种理解是否正确,它如何适应allocator_traits?

  4. 中的静态成员函数

你似乎忽略了一个事实,即allocator_traits中的所有静态成员函数都将Alloc &作为第一个参数。也就是说,他们使用分配器类型的对象来完成他们的工作。

"access an allocator through allocator_traits only" 的这一政策的原因是 allocator_traits 的一些成员提供了分配器操作的默认实现,如果分配器类型本身没有提供的话。这适用于在 C++11 中添加到分配器要求但在 C++03 中不存在的所有成员。一个示例是 construct,如果分配器类型不提供合适的 construct 函数,它将调用放置 new 运算符 ::new。因此,这些默认值允许为 C++03 编写的分配器在 C++11 容器中保持不变。

此外,使用 allocator_traits 可以实现更多的可定制性。 allocator_traits 可以指定给特定的分配器 class 并且特征函数可以通过对 Alloc & 参数的不同调用来实现。

所以您关于实例化 allocator_type 的假设是正确的。区别在于你不应该直接调用它的成员函数(因为它们可能不存在),而是通过 allocator_traits.

中的静态访问器

On the other hand, the allocator_traits in C++11 seem to imply the following usage:

std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);

不,您错过了该函数调用的最重要参数:分配器。

I guess this static allocate member function will probably create a temporary ad-hoc instance of allocator_type via its default constructor.

不,因为您将分配器参数传递给函数。

What will happen if allocator_type is a stateful allocator?

它工作正常,因为您将该有状态分配器作为参数传递给使用它的函数。

Why should I instantiate allocator_type at all and bother with stuff like EBO if I can directly use the static member functions in allocator_traits instead?

因为你不能用它们代替。

As stated before, my understanding is that any class-like template parameters should be instantiated inside my container class in order to allow for stateful versions of these parameters. Is this understanding correct, and how does it fit with the static member functions in allocator_traits?

是的,你的理解是正确的,如果你使用得当,它和allocator_traits很吻合。

allocator_traits 的要点是为大多数分配器接口提供合理的默认值。这有两个目的:

  • 首先在C++11中定义分配器更简单(你只需要提供value_typeallocatedeallocate、模板构造函数用于重新绑定分配器和 operator==operator!=),因此现在编写简单的自定义分配器要简单得多。

  • 其次,它允许仅满足 C++03 分配器要求的现有分配器被 C++11 容器使用。 C++03 分配器没有定义嵌套成员,例如 C++11 容器寻找的 propagate_on_container_swap,或者允许使用任何参数构造对象的新可变参数 construct(pointer, Args&&...) 成员,而不仅仅是复制构造(这是允许 emplace 工作的原因)。因此,通过在 allocator_traits 中包装分配器的使用,大多数 Allocator 接口都被赋予了合理的默认值,因此现有的 C++03 代码使用带有容器(如 std::vector 的自定义分配器不会突然失败如果使用 C++11 重新编译,则构建。 std::vector 实现仅通过 allocator_traits 类型使用新成员,因此自定义分配器未更新以提供属于 C++11 的所有新成员并不重要分配器要求。