首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::allocator_traits<A>的使用

std::allocator_traits<A>的使用
EN

Stack Overflow用户
提问于 2012-03-13 17:50:21
回答 1查看 7.5K关注 0票数 10

我想设计一个类模板,它使用一个分配器类型(如标准17.6.3.5节中定义的那样)作为模板参数。我看到了std::allocator_traits<A>如何用默认设置来帮助填充缺少的A成员。除此之外,标准库或boost中是否有有助于正确使用分配程序的内容?

特别是:

  1. 为了纪念std::allocator_traits<A>::propagate_on_container_copy_assignment这样的类型,我必须在每个类的特殊成员函数中检查这些东西吗?每个类都有一个A类型的成员?或者我是否可以使用一些包装器类型作为成员来处理这些问题?如果我想通过在用户可见对象旁边存储额外的数据来减少分配的数量,
  2. 是否应该重新绑定这样的分配器?

代码语言:javascript
复制
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));
    }
    //...
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-16 00:35:46

我不知道有什么可以让生活变得更简单,allocator_traits确实通过提供所有的样板代码来简化分配器的编写,但它无助于使用分配器。

为了在C++03和C++11代码中使用单个分配程序API (我在GCC 4.7中添加了<ext/alloc_traits.h> ),类模板__gnu_cxx::__alloc_traits提供了一个一致的API,它在C++11模式中使用allocator_traits,并在C++03模式下直接调用分配程序上的相关成员函数。

  1. 不,没有包装器或快捷方式,C++11分配器的要求使容器作者的工作更加复杂。每个容器的需求略有不同,这取决于它如何管理内存。对于类似向量的类型,在复制赋值操作符中,如果propagate_on_container_copy_assignment为false,且现有容量大于源对象的大小,则可以重用现有内存(如果

为true,且新的分配器不相等,则不能重用旧内存,因为在替换分配程序之后不可能对其进行重新分配),但这种优化对于基于节点的容器(如列表或映射)没有多大帮助。

  1. 看起来几乎是正确的,尽管您可能希望替换它。

返回::new(&sp->m_obj) T(std::move(obj));

使用

a(m_alloc);std::allocator_traits::construct(a,&sp->m_obj,std::move(obj));返回&sp->m_obj;

如前所述,使用分配程序的容器使用allocator_traits<A>::construct创建元素类型T本身,但是分配的任何其他类型(例如storage)都不能使用construct

如果storage本身是构造的,那么它将构造storage::m_obj,除非该成员是一个可以保留未初始化的类型,如std::aligned_storage<sizeof(T)>,该类型可以在以后由allocator_traits<A>::construct显式初始化。或者,单独构造需要非平凡结构的每个成员,例如,如果storage也有一个string成员:

代码语言:javascript
复制
    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_strm_obj成员需要非平凡的初始化,因此它们的生存期是在构造函数完成时开始的,这分别是通过placement和construct调用完成的。

编辑:我最近了解到该标准有一个缺陷(我已经报告过),对construct的调用不需要使用回弹分配器,所以这些行:

代码语言:javascript
复制
    A a(m_alloc);    
    std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj));

可替换为:

代码语言:javascript
复制
    std::allocator_traits<storage_alloc>::construct(m_alloc, &sp->m_obj, std::move(obj));

这会让生活稍微轻松一些。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9689328

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档