propagate_on_container_move_assignment的示例用法

时间:2014-12-14 15:56:53

标签: c++ c++11 allocator

我试图了解如何正确编写AllocatorAware容器。

我的理解是propagate_on_container_move_assignment typedef指示在移动分配Container本身时是否需要复制某个Allocator类型。

所以,既然我找不到任何这方面的例子,我自己的抨击就像下面这样:

给定容器类型ContainerAllocator类型allocator_type和内部allocator_type数据成员m_alloc

Container& operator = (Container&& other)
{
  if (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
  {
     m_alloc = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
      other.m_alloc
     );
  }

  return *this;
}

这是对的吗?

此外,另一个混乱的来源是嵌套的typedef propagate_on_container_move/copy_assignment专门讨论赋值 ...但是构造函数呢? AllocatorAware容器的移动构造函数或复制构造函数是否需要检查这些typedef?我认为这里的答案是 ...,意思是,我还需要写:

Container(Container&& other)
{
      if (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
      {
         m_alloc = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
          other.m_alloc
         );
      }
}

1 个答案:

答案 0 :(得分:20)

我建议您研究libc++<vector>标题。您必须处理std :: lib实现者需要使用的所有令人讨厌的下划线。但是libc ++有一个符合C ++ 11的实现,用于检查。

移动作业运算符

容器移动赋值运算符必须处理三种不同的可能性:

  1. propagate_on_container_move_assignment是真的。
  2. propagate_on_container_move_assignment为false,而lhs和rhs的分配器相等。
  3. propagate_on_container_move_assignment是假的,来自lhs和rhs的分配器比较不等。
  4. 如果可能,这三种情况之间的决定应该在编译时进行,而不是在运行时进行。具体来说,应该在编译时在集合{1}和{2,3}之间进行选择,因为propagate_on_container_move_assignment是编译时常量。编译时常量的编译时分支通常使用tag dispatching来完成,而不是在显示时使用if语句。

    在这些情况下都不应使用select_on_container_copy_construction。该函数仅为容器拷贝构造函数的

    在情况1中,lhs应首先使用lhs的分配器来释放已分配的所有内存。这必须首先完成,因为rhs分配器可能无法在以后释放此内存。然后lhs分配器从rhs分配器移动分配(就像任何其他移动分配一样)。然后将内存所有权从rhs容器传输到lhs容器。如果你的容器的设计是这样的,rhs容器不能处于无资源状态(一个糟糕的设计imho),那么一个新的资源可以由rhs分配器移动到rhs容器。

    propagate_on_container_move_assignment为false时,您必须在运行时选择案例2和3,因为分配器比较是运行时操作。

    在案例2中,您可以执行与案例1相同的操作,之外不要移动分配分配器。跳过这一步。

    在案例3中,您无法将任何内存的所有权从rhs容器转移到lhs容器。你唯一能做的就是:

    assign(make_move_iterator(rhs.begin()), make_move_iterator(rhs.end()));
    

    请注意,在案例1中,由于算法是在编译时选择的,因此容器的value_type不必是MoveAssignable也不是MoveInsertableMoveConstructible)移动 - 分配容器。但在案例2中,value_type s 必须是MoveAssignableMoveInsertableMoveConstructible),即使它们从来都不是,因为你在运行时选择2到3之间。并且3需要value_type上的这些操作来执行assign

    移动赋值运算符很容易成为容器实现的最复杂的特殊成员。其余的更容易:

    移动构造函数

    移动构造函数只是移动构造分配器并窃取来自rhs的资源。

    复制构造函数

    复制构造函数从select_on_container_copy_construction(rhs.m_alloc)获取其分配器,然后使用它为复制分配资源。

    复制分配运算符

    复制赋值运算符必须首先检查propagate_on_container_copy_assignment是否为真。如果是,并且如果lhs和rhs分配器比较不相等,那么lhs必须首先释放所有内存,因为它在分配器被复制分配后不能再这样做。接下来,如果propagate_on_container_copy_assignment,则复制分配分配器,否则不分配。然后复制元素:

    assign(rhs.begin(), rhs.end());