标准::allocator_traits<A>的使用
Use of std::allocator_traits<A>
我想设计一个以分配器类型(如标准第17.6.3.5节中所定义)为模板参数的类模板。我看到std::allocator_traits<A>
如何使用默认设置来帮助填充A
的任何丢失成员。除此之外,标准库或boost中是否有任何东西可以帮助正确使用分配器?
特别是:
-
为了尊重像
std::allocator_traits<A>::propagate_on_container_copy_assignment
这样的typedef,我是否必须在每个具有类型A
成员的类的特殊成员函数中检查这些东西?或者有没有一些包装器类型可以作为成员使用,来处理这些东西? -
如果我想通过在用户可见对象旁边存储额外数据来过度分配以减少分配数量,那么像这样重新绑定分配器合适吗?
template<typename T, typename A>
class MyClass
{
private:
//...
struct storage {
int m_special_data;
T m_obj;
};
typedef typename std::allocator_traits<A>::template rebind_alloc<storage>
storage_alloc;
typedef typename std::allocator_traits<A>::template rebind_traits<storage>
storage_traits;
storage_alloc m_alloc;
static T* alloc(T&& obj)
{
storage_traits::pointer sp = storage_traits::allocate(m_alloc, 1);
sp->m_special_data = 69105;
return ::new(&sp->m_obj) T(std::move(obj));
}
//...
};
我不知道有什么能让生活更轻松,allocator_traits
通过提供所有样板代码,确实让编写分配器变得更简单,但它对使用分配器没有帮助。
为了在C++03和C++11代码中使用一个分配器API,我将<ext/alloc_traits.h>
添加到GCC 4.7中,类模板__gnu_cxx::__alloc_traits
提供了一个一致的API,它在C++11模式中使用allocator_traits
,并在C++03模式中直接在分配器上调用相关的成员函数。
-
不,没有包装器或快捷方式,C++11分配器的要求使容器作者的工作变得更加复杂。根据容器管理内存的方式,每个容器的要求略有不同。对于类矢量类型,在复制分配运算符中,如果
propagate_on_container_copy_assignment
(POCCA)为false,并且现有容量大于源对象的大小,则可以重用现有内存(如果POCCA为true,并且新分配器不相等,则不能重用旧内存,因为在分配器被替换后,以后不可能取消分配),但这种优化对基于节点的内存没有多大帮助容器,如列表或映射。 -
这看起来几乎是正确的,尽管你可能想取代
return ::new(&sp->m_obj) T(std::move(obj));
带有
A a(m_alloc); std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj)); return &sp->m_obj;
如[container.requirements.general]/3中所述,使用分配器的容器使用allocator_traits<A>::construct
来创建元素类型T
本身,但分配的任何其他类型(如storage
)都不得使用construct
。
如果storage
本身被构造,则它将构造storage::m_obj
,除非该成员是可以保持未初始化的类型,例如std::aligned_storage<sizeof(T)>
,其稍后可以由allocator_traits<A>::construct
显式初始化。或者,单独构建每个需要非平凡构建的成员,例如,如果storage
也有string
成员:
storage_traits::pointer sp = storage_traits::allocate(m_alloc, 1);
sp->m_special_data = 69105;
::new (&sp->m_str) std::string("foobar");
A a(m_alloc);
std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj));
return &sp->m_obj;
m_special_data
成员是一个平凡的类型,因此一旦为其分配了存储,其生存期就开始了。m_str
和m_obj
成员需要非平凡的初始化,因此它们的生存期在构造函数完成时开始,这分别由placementnew和construct
调用完成。
编辑:我最近了解到该标准有一个缺陷(我已经报告了),并且对construct
的调用不需要使用反弹分配器,所以这些行:
A a(m_alloc);
std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj));
可以替换为:
std::allocator_traits<storage_alloc>::construct(m_alloc, &sp->m_obj, std::move(obj));
这让生活稍微轻松一些。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中