根据N3485§23.3.2.2:
(...)数组的隐式移动构造函数和移动赋值运算符要求T分别为 MoveConstructible 或 MoveAssignable 。 / p>
因此,std::array
支持移动语义,如果其元素的类型确实如此。太好了!
然而,这究竟意味着什么?我倾向于将此类型描述为提供符合STL标准的接口的更安全版本的数组,但如果这是真的,那么std::array
如何移动构造其元素?我可以用普通数组做同样的事吗?
答案 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已经回答了很多细节。
这个看起来像是一个完整的例子: