gig*_*tes 18 c++ memory-management c++11
我正在开发一个类似容器的类,我想使用标准的分配器基础结构,就像标准容器一样.在网上我找到了很多关于如何std::allocator单独使用该类的材料,或者如何为标准容器定义自定义分配器,但是关于如何一般地使用标准符合分配器的材料是非常罕见的,特别是在C++ 11的上下文,从谁编写自定义分配器的角度来看,事情似乎要容易得多,但从容器的角度来看更复杂.
所以我的问题是如何以最通用的方式正确使用标准的符合标准的分配器,具体来说:
我对C++ 11世界的答案特别感兴趣(它在C++ 14中有什么改变吗?)
How*_*ant 20
在下面的所有答案中,我假设您要遵循C++ 11标准定义容器的规则.该标准不要求您以这种方式编写自定义容器.
- 首先,我应该何时以这种方式设计自定义容器?使用默认分配器而不是普通的新/删除是否有明显的性能开销(包括缺少优化机会)?
自定义分配器最常见和最有效的用途之一是出于性能原因将其分配到堆栈.如果您的自定义容器无法接受此类分配器,则您的客户端将无法执行此类优化.
- 我是否必须显式调用包含对象的析构函数?
你必须显式调用allocator_traits<allocator_type>::destroy(alloc, ptr),然后直接调用value_type析构函数,或者调用destroy成员allocator_type.
- 如何区分有状态和无状态分配器?
我不打扰.假设分配器是有状态的.
- 如何处理有状态分配器?
请仔细遵循C++ 11中规定的规则.特别是那些在[container.requirements.general]中指定的分配器感知容器.规则太多,无法在此列出.但是,我很乐意回答有关这些规则的具体问题.但是第一步是获得标准的副本,并阅读它,至少是容器需求部分.为此,我推荐最新的C++ 14工作草案.
- 当(如果有的话)两个实例可以互换时(何时可以用一个实例销毁分配给另一个实例的内存)?
如果两个分配器比较相等,则可以解除分配从另一个分配的指针.副本(通过复制构造或复制分配)需要比较相等.
- 复制容器时必须复制它们?
搜索标准propagate_on和select_on_container_copy_construction细节.简而言之,答案是"这取决于".
- 移动容器时可以/必须移动它们吗?
必须为移动建设.移动分配取决于propagate_on_container_move_assignment.
- 在容器的移动构造函数和移动赋值运算符中,何时可以将指针移动到已分配的内存,何时必须分配不同的内存并移动元素?
新移动的构造容器应该通过移动构造rhs的分配器来获得它的分配器.这两个分配器需要比较相等.因此,您可以为所有已分配的内存传输内存所有权,对于该指针,容器具有该指针nullptr位于rhs中的有效状态.
移动赋值运算符可以说是最复杂的:行为取决于propagate_on_container_move_assignment两个分配器是否相等.以下是我的"分配器备忘单"中更完整的描述.
- 在这种情况下是否存在关于异常安全的问题?
是的,吨.[allocator.requirements]列出了容器可以依赖的分配器要求.这包括哪些操作可以和不可以抛出.
您还需要处理分配器pointer实际上不是a 的可能性value_type*.[allocator.requirements]也是查找这些细节的地方.
祝好运.这不是一个初学者项目.如果您有更具体的问题,请将其发布到SO.要开始,请直接进入标准.我不知道有关该主题的任何其他权威来源.
这是我为自己制作的备忘单,描述了分配器行为和容器的特殊成员.它用英文写成,而不是标准版.如果您发现我的备忘单和C++ 14工作草案之间存在任何差异,请相信工作草案.一个已知的差异是我noexcept以标准没有的方式添加了规格.
分配器行为:
Run Code Online (Sandbox Code Playgroud)C() noexcept(is_nothrow_default_constructible<allocator_type>::value); C(const C& c);从中获取分配器
alloc_traits::select_on_container_copy_construction(c).Run Code Online (Sandbox Code Playgroud)C(const C& c, const allocator_type& a);从中获取分配器
a.Run Code Online (Sandbox Code Playgroud)C(C&& c) noexcept(is_nothrow_move_constructible<allocator_type>::value && ...);从中获取分配器
move(c.get_allocator()),传输资源.Run Code Online (Sandbox Code Playgroud)C(C&& c, const allocator_type& a);从中获取分配器
a.如果转移资源a == c.get_allocator().从每个c[i]if 移动构造a != c.get_allocator().Run Code Online (Sandbox Code Playgroud)C& operator=(const C& c);如果
alloc_traits::propagate_on_container_copy_assignment::value是true,则复制分配分配器.在这种情况下,如果分配器在分配之前不相等,则转储所有资源*this.Run Code Online (Sandbox Code Playgroud)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].Run Code Online (Sandbox Code Playgroud)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.