对类

时间:2015-10-05 09:47:41

标签: c++ memory-management stl c++14 allocator

给定一个非无状态自定义分配器A(比如,竞技场分配器,绑定到运行时已知大小的某个连续内存块)和类S,包含AllocatorAwareContainer的文件类型:

struct S
{
    A() = default;
    // another c-tors
    std::vector< T > v;
    std::shared_ptr< U > s;
};

我想将A用于类S的子集(甚至是所有) AllocatorAwareContainer 字段。很明显,我应该为类S提供另一个模板参数,并相应地更改所有有趣数据成员的类型,如下所示:

template< typename A = std::allocator< void > >
struct S
{
    // c-tors
    template< typename X >
    using allocator = typename std::allocator_traits< A >::template rebind< X >::other;
    std::vector< T, allocator< T > > v;
    std::shared_ptr< U, allocator< U > > s;
};

当前构造函数和其他构造函数的变化(假设A不是 DefaultConstructible ,并且可能存在任何其他可能的限制)我应该做什么?

我应该将分配器A存储在课程S的其他字段中吗?

为类使用自定义分配器有哪些一般提示?

1 个答案:

答案 0 :(得分:1)

我习惯使用来自bsl的容器,它们是分配器感知的,并且用于创建分配器感知类。标准容器及其分配器使用的主要区别是bsl使用指向分配器基类(bslma::Allocator)的指针。这种方法很好地摆脱了std::rebind - 舞蹈,这使得已经相对复杂的领域的问题变得复杂。否则,我认为这些概念可以转化。我没有使用带有标准库容器的分配器的经验。

使用分配器有两个基本规则,这些规则在实践中运作良好:

  1. 对象的分配器在构造后更改。
  2. 每个支持allocator的类型都应将作为构造函数参数接收的分配器传递给所有支持分配器的成员。
  3. 第二条规则意味着类的构造者需要照顾其所有成员。在已知成员类型的情况下,确定是否需要分配器以及如何构造分配器是相当直接的。当成员类型以某种形式是通用的,即它依赖于某种形式的模板参数时,通常不知道是否需要分配器。

    当不清楚成员是否需要接收分配器时,使用bsl时使用的方法是保持包裹成员。更具体地说,成员将持有bslalg::ConstructorProxy<T>,其将静态地确定T支持构造函数采用分配器和适当的传递分配器与否。