【问题标题】:Move constructors and `std::array`移动构造函数和`std::array`
【发布时间】:2014-05-02 01:56:02
【问题描述】:

根据 N3485 §23.3.2.2:

(...) array 的隐式移动构造函数和移动赋值运算符要求 T 分别为 MoveConstructibleMoveAssignable

所以,std::array 支持移动语义,如果它的元素类型支持的话。太好了!

但是,这究竟意味着什么?我倾向于将此类型描述为提供符合 STL 的接口的数组的更安全版本,但如果这是真的,那么std::array 如何移动构造其元素?我可以对普通数组做同样的事情吗?

【问题讨论】:

    标签: c++ c++11 move-semantics


    【解决方案1】:

    但是,这究竟意味着什么?

    这意味着,如果元素类型是可移动的,那么数组类型也是。

    std::array<movable, 42> move_from = {...};
    std::array<movable, 42> move_to = std::move(move_from); // moves all the elements
    

    我倾向于将此类型描述为提供 STL 兼容接口的数组的更安全版本

    不是真的。它是一个数组的包装器,赋予它与聚合类相同的语义 - 包括复制和移动它的能力。

    std::array 如何移动构造它的元素?

    与任何其他聚合的方式完全相同。它的隐式移动构造函数将移动构造它的所有成员,包括任何成员数组的元素。

    我可以对普通数组做同样的事情吗?

    仅当您将其包装在类类型中时,如 std::array 所做的那样。

    【讨论】:

    • “只有当你将它包装在一个类类型中” 所以事实上它是一个用户定义的类型才允许这种行为......有趣。
    • @faranwath:确实——具体来说,用户定义的聚合类型已经隐式生成了移动构造函数。
    【解决方案2】:

    移动std::array 不同于移动std::vector。将一个 std::vector 移动到另一个时,(有时*)可以简单地重新定位内部指针并完全避免操作元素。

    对于std::array,这当然是不可能的——它的元素具有自动存储持续时间,它们实际上包含在对象中。但是,它们中的每一个仍然可以移动,这就是 std::array 上的移动操作所做的**。

    * 假设分配器是兼容的并且不禁止这个操作

    ** 当缓冲区不能仅由目标向量重新拥有时,这也是您使用 std::vector 获得的结果。

    【讨论】:

      【解决方案3】:

      (非联合)类的默认移动构造函数执行成员移动。移动原始数组数据成员意味着移动数组的每个元素,请参阅 [class.copy]/15。

      因此,您可以通过将原始数组放入类中来移动它:

      struct wrap
      {
          std::string arr[25];
      };
      
      auto w = wrap();
      auto m = std::move(w); // moves the 25 `std::string`s
      

      也可以手动调用元素的移动构造函数,例如:

      std::string a[3] = { /*...*/ };
      std::string b[3] = {std::move(a[0]), std::move(a[1]), std::move(a[2])};
      

      如果std::array 包含原始数组,则未指定。但是,它确实包含value_type 的数据成员,因为它保证是一个聚合。调用移动构造函数时,这些数据成员将按上述方式移动。

      如果 std::array 的数据成员不是 MoveConstructible,则实例化其移动构造函数将失败。

      【讨论】:

      • “因此,您可以通过将原始数组放入类中来移动它” Mike Seymour 也指出了这一点,但我并不知道——尽管现在想来,是有道理的。
      【解决方案4】:

      您可以使用“展示位置new”来实现。您会发现很多 questions on placement new 已经回答了很多详细信息。

      这个好像有一个完整的例子:

      【讨论】:

      • 没想到!
      猜你喜欢
      • 2013-08-08
      • 1970-01-01
      • 2016-05-31
      • 2015-02-14
      • 2014-03-13
      • 2011-11-25
      • 2015-03-16
      • 2018-03-12
      • 2015-04-26
      相关资源
      最近更新 更多