移动构造函数和`std :: array`

时间:2014-03-24 15:41:21

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

根据N3485§23.3.2.2:

  

(...)数组的隐式移动构造函数和移动赋值运算符要求T分别为 MoveConstructible MoveAssignable 。 / p>

因此,std::array支持移动语义,如果其元素的类型确实如此。太好了!

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

4 个答案:

答案 0 :(得分:26)

  

然而,这究竟意味着什么?

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

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才会。

答案 1 :(得分:21)

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

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

*假设分配器兼容并且不禁止此操作

**当缓冲区不能被目标向量重新拥有时,这也是{{1}}所得到的。

答案 2 :(得分:7)

(非联合)类的默认移动构造函数执行成员移动。移动原始数组数据成员意味着移动每个数组的元素,请参阅[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,则实例化其移动构造函数将失败。

答案 3 :(得分:0)

您可以使用&#34;展示位置new&#34;来完成。你会发现很多questions on placement new已经回答了很多细节。

这个看起来像是一个完整的例子: