我应该在我的 class 中有一个分配器作为成员变量吗?

Should I have an Allocator as a member variable in my class?

如果我想制作一个使用 allocators 的 class(如自定义字符串 class),我是否应该将 allocator 实例化为 [=13] =] 还是不?

// 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 ?

我的问题是我正在尝试制作一个 space 高效的字符串 class,它只存储 char pointer(在 std::variant along with small primitive types), but having the allocator as a member doubles the size of my object even with an empty stateless allocator (like std::allocator 中使用它) .

如果您打算仅使用默认值 standard library allocator,那么您不必在 class.

中将分配器作为字段保留

The std::allocator class template is the default Allocator used by all standard library containers if no user-specified allocator is provided. The default allocator is stateless, that is, all instances of the given allocator are interchangeable, compare equal and can deallocate memory allocated by any other instance of the same allocator type.

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

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

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

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

对于空 class Empty_allocator, sizeof(S<Empty_allocator>) 将等于 sizeof(int).

如果没有此属性,标准技巧是使用 empty base class optimization,从分配器本身派生出 class。例如,在 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;
    };