【问题标题】:Should I have an Allocator as a member variable in my class?我应该在我的班级中有一个分配器作为成员变量吗?
【发布时间】:2019-11-15 12:06:11
【问题描述】:

如果我想创建一个使用allocators 的类(如自定义字符串类),我是否应该将allocator 实例化为member variable

// Should I do this ?
template <class Allocator>
class my_class {
    Allocator a_;

    void func_that_allocates() {
        std::allocator_traits<Allocator>::allocate(a_, 10);
    }
};

// Or this ?
template <class Allocator>
class my_class {
    void func_that_allocates() {
        std::allocator_traits<Allocator>::allocate(Allocator(), 10);
    }
};

// Or maybe have a_ be a static member ?

我的问题是我正在尝试创建一个节省空间的字符串类,它只存储 char pointer(在 std::variant 以及小的原始类型中使用它),但将 allocator 作为即使使用空的stateless allocator(如std::allocator),成员也会使我的对象的大小翻倍。

【问题讨论】:

  • 我记得读过所有分配器实例都是可互换的。因此,如果它成立,您可以像您的第二个版本一样传递一个未命名的临时对象。
  • 我认为您可能指的是 Allocator::is_always_equal (参见表格底部的name requirements),它告诉您两个实例对于特定的分配器类型是否可以互换,但遗憾的是不是分配器的要求。
  • 你甚至不能假设Allocator默认可构造,所以你需要从用户那里得到一个Allocator实例。

标签: c++ allocator


【解决方案1】:

即使分配器为空,它仍然会影响对象大小。在 C++20 中,我们将使用 [[no_unique_address]] attribute 来解决这个问题(现在在 GCC 9 和 Clang 9 中实现)。你可以写:

template<class Alloc>
class S {
    int member;
    [[no_unique_address]] Alloc allocator_;
};

对于空类Empty_allocatorsizeof(S&lt;Empty_allocator&gt;) 将等于sizeof(int)

如果没有这个属性,标准技巧是使用empty base class optimization,从分配器本身派生你的类。例如,在 libstdc++ 的 std::vector 实现中使用了这种方法:

  template<typename Tp, typename Alloc>
    struct Vector_base
    {
      typedef typename __gnu_cxx::__alloc_traits<Alloc>::template
          rebind<Tp>::other Tp_alloc_type;

      struct Vector_impl : public Tp_alloc_type
      { ... };

      const Tp_alloc_type& M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
      { return *static_cast<const Tp_alloc_type*>(&this->M_impl); }

      Alloc get_allocator() const _GLIBCXX_NOEXCEPT
      { return Alloc(M_get_Tp_allocator()); }

      Vector_impl& M_impl;
    };

【讨论】:

    【解决方案2】:

    如果您打算只使用默认的standard library allocator,那么您不必将分配器作为您的类中的一个字段。

    std::allocator 类模板是所有使用的默认分配器 如果没有用户指定的分配器,则为标准库容器 假如。默认分配器是无状态的,即所有实例 给定的分配器是可互换的,比较相等并且可以 释放由任何其他相同实例分配的内存 分配器类型

    当您使用模板时 - API 用户可以指定一些自定义状态完整分配器,在这种情况下您将需要一个字段。

    您也可以直接使用new[]/delete[],而无需任何分配器。或者您可以重写func_that_allocates 以便仅使用堆栈内存。即替换:任何std::vectorstd::array 任何std::stringchar tmp_str[128] = {'\0'}; 等。

    【讨论】:

      猜你喜欢
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多