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

我的理解是propagate_on_container_move_assignment typedef指示在移动容器本身时是否需要复制某种Allocator类型。

因此,由于找不到任何示例,因此我自己的尝试将如下所示:

给定一个容器类型Container,一个Allocator类型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容器的move构造函数或copy构造函数是否还需要检查这些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
         );
      }
}

最佳答案

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

移动分配运算符

容器移动分配运算符(operator)必须处理三种单独的可能性:

  • propagate_on_container_move_assignment为true。
  • propagate_on_container_move_assignment为false,lhs和rhs中的分配器比较相等。
  • propagate_on_container_move_assignment为false,来自lhs和rhs的分配器比较不相等。

  • 如果可能,这三种情况之间的决定应在编译时而不是运行时做出。具体来说,由于propagate_on_container_move_assignment是一个编译时间常数,因此应该在编译时在集{1}和{2,3}之间进行选择。在编译时常量上的编译时分支通常是使用tag dispatching完成的,而不是使用如所示的if语句。

    在所有这些情况下,都不应该使用select_on_container_copy_construction。该功能仅适用于容器复制构造函数。

    在情况1中,lhs应该首先使用lhs的分配器来释放所有已分配的内存。必须首先完成此操作,因为rhs分配器以后可能无法取消分配此内存。然后,从rhs分配器对lhs分配器进行移动分配(就像其他任何移动分配一样)。然后将内存所有权从rhs容器转移到lhs容器。如果您的容器设计不能使rhs容器处于无资源状态(糟糕的设计恕我直言),则可以通过从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不必是MoveAssignableMoveInsertable(MoveConstructible)即可移动分配容器。但是在第2种情况下,value_type确实必须是MoveAssignableMoveInsertable(MoveConstructible),即使它们从来没有,因为在运行时您要在2到3之间进行选择。 3需要对value_type进行这些操作以执行assign

    移动分配运算符很容易成为实现容器最复杂的特殊成员。其余的要容易得多:

    移动构造函数

    move构造函数只是move构造分配器,并从rhs中窃取资源。

    复制构造函数

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

    复制分配运算符

    复制分配运算符(operator)必须首先检查propagate_on_container_copy_assignment是否为true。如果是这样,并且如果lhs和rhs分配器比较不相等,则lhs必须首先释放所有内存,因为在分配分配器之后,它将无法进行分配。接下来,如果是propagate_on_container_copy_assignment,则复制分配分配器,否则不分配。然后复制元素:
    assign(rhs.begin(), rhs.end());
    

    关于c++ - 用法propagate_on_container_move_assignment的示例用法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27471053/

    10-11 18:10