在下面的所有答案中,我假设您要遵循 C++11 标准定义容器的规则。该标准不要求您以这种方式编写自定义容器。
- 首先,我什么时候应该用这种方式设计自定义容器?是否存在合理的性能开销(包括缺失
优化机会)在使用默认分配器而不是
简单的新建/删除?
出于性能原因,自定义分配器最常见和最有效的用途之一是让它在堆栈外分配。如果您的自定义容器不能接受这样的分配器,那么您的客户端将无法执行这样的优化。
您必须显式调用allocator_traits<allocator_type>::destroy(alloc, ptr),这又会直接调用value_type 的析构函数,或者调用allocator_type 的destroy 成员。
我不会打扰。假设分配器是有状态的。
非常小心地遵循 C++11 中规定的规则。特别是那些在 [container.requirements.general] 中指定的分配器感知容器。规则太多,这里就不一一列举了。不过,我很乐意回答有关任何这些规则的具体问题。但第一步是获取标准的副本,并阅读它,至少是容器要求部分。为此我推荐the latest C++14 working draft。
- 什么时候(如果有的话)两个实例可以互换(我什么时候可以用一个实例销毁分配给另一个实例的内存)?
如果两个分配器比较相等,那么任何一个都可以释放从另一个分配的指针。副本(通过复制构造或复制分配)需要比较相等。
在标准中搜索 propagate_on 和 select_on_container_copy_construction 以获取详细信息。简单的回答是“视情况而定”。
必须用于移动构造。移动分配取决于propagate_on_container_move_assignment。
- 在容器的移动构造函数和移动赋值运算符中,何时可以将指针移动到分配的内存,何时必须分配不同的内存
而是移动元素?
新的 move 构造的容器应该通过 move 构造 rhs 的分配器来获得它的分配器。这两个分配器需要比较相等。因此,您可以转移所有已分配内存的内存所有权,您的容器对于该指针的有效状态为 rhs 中的 nullptr。
移动赋值运算符可以说是最复杂的:行为取决于propagate_on_container_move_assignment 以及两个分配器是否比较相等。更完整的描述在我的“分配器备忘单”中。
是的,吨。 [allocator.requirements] 列出容器可以依赖的分配器要求。这包括哪些操作可以抛出,哪些不能抛出。
您还需要处理分配器的pointer 实际上不是value_type* 的可能性。 [allocator.requirements] 也是寻找这些细节的地方。
祝你好运。这不是一个初学者项目。如果您有更具体的问题,请将它们发布到 SO。要开始,请直接进入标准。我不知道有关该主题的任何其他权威来源。
这是我为自己制作的一份备忘单,其中描述了分配器的行为以及容器的特殊成员。它是用英文写的,不是标准的eze。如果您发现我的备忘单和 C++14 工作草案之间有任何差异,请相信工作草案。一个已知的差异是我添加了noexcept 规范,而标准没有。
分配器行为:
C() noexcept(is_nothrow_default_constructible<allocator_type>::value);
C(const C& c);
从alloc_traits::select_on_container_copy_construction(c)获取分配器。
C(const C& c, const allocator_type& a);
从a获取分配器。
C(C&& c)
noexcept(is_nothrow_move_constructible<allocator_type>::value && ...);
从move(c.get_allocator())获取分配器,转移资源。
C(C&& c, const allocator_type& a);
从a 获取分配器。如果a == c.get_allocator(),则传输资源。
如果a != c.get_allocator(),则从每个c[i] 移动构造。
C& operator=(const C& c);
如果alloc_traits::propagate_on_container_copy_assignment::value 是true,
复制分配分配器。在这种情况下,如果分配器先验不相等
分配,从*this转储所有资源。
C& operator=(C&& c)
noexcept(
allocator_type::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value);
如果alloc_traits::propagate_on_container_move_assignment::value 是true,
转储资源,移动分配分配器,并从c 转移资源。
如果alloc_traits::propagate_on_container_move_assignment::value 是false
和get_allocator() == c.get_allocator(),转储资源,转移
来自c的资源。
如果alloc_traits::propagate_on_container_move_assignment::value 是false
和get_allocator() != c.get_allocator(),移动分配每个c[i]。
void swap(C& c)
noexcept(!allocator_type::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
如果alloc_traits::propagate_on_container_swap::value 是true,则交换
分配器。无论如何,交换资源。未定义的行为,如果
分配器不相等,propagate_on_container_swap::value 是 false。