Namespaces
Variants

std:: move

From cppreference.net
Utilities library
定义于头文件 <utility>
template < class T >
typename std:: remove_reference < T > :: type && move ( T && t ) noexcept ;
(C++11 起)
(C++14 前)
template < class T >
constexpr std:: remove_reference_t < T > && move ( T && t ) noexcept ;
(C++14 起)

std::move 用于 指示 对象 t 可以被“移动”,即允许将资源从 t 高效地转移至另一对象。

具体而言, std::move 会生成一个 xvalue表达式 ,该表达式标识其参数 t 。它完全等价于转换为右值引用类型的 static_cast 操作。

目录

参数

t - 待移动的对象

返回值

static_cast < typename std:: remove_reference < T > :: type && > ( t )

注释

接受右值引用参数的函数(包括 移动构造函数 移动赋值运算符 ,以及常规成员函数如 std::vector::push_back )在通过 重载决议 被调用时,会匹配 右值 实参(包括 纯右值 如临时对象,或 亡值 如通过 std::move 生成的对象)。若实参标识了资源持有对象,这些重载函数可以选择(但非必须)转移实参所持有的资源。例如,链表的移动构造函数可以复制指向链表头节点的指针,并在实参中存储 nullptr ,而无需重新分配和复制每个独立节点。

右值引用变量的名称是左值,必须转换为亡值才能绑定到接受右值引用参数的函数重载,这就是为什么移动构造函数和移动赋值运算符通常使用 std::move

// 简单移动构造函数
A(A&& arg) : member(std::move(arg.member)) // 表达式 "arg.member" 是左值
{}
// 简单移动赋值运算符
A& operator=(A&& other)
{
    member = std::move(other.member);
    return *this;
}

一种例外情况是当函数参数类型为 转发引用 (形式上类似于类型模板参数的右值引用)时,此时应改用 std::forward

除非另有说明,所有被移动的标准库对象都会处于"有效但未指定的状态",这意味着该对象的类不变式仍然成立(因此没有前置条件的函数,例如赋值运算符,在对象被移动后仍可安全使用):

std::vector<std::string> v;
std::string str = "example";
v.push_back(std::move(str)); // str 当前有效但状态未指定
str.back(); // 若 size() == 0 则行为未定义:back() 有前置条件 !empty()
if (!str.empty())
    str.back(); // 正确,empty() 无前置条件且 back() 前置条件已满足
str.clear(); // 正确,clear() 无前置条件

此外,以xvalue实参调用的标准库函数可以假定该实参是对象的唯一引用;如果它是通过 std::move 从左值构造而来,则不会进行别名检查。然而,标准库类型的自移动赋值保证将对象置于有效(但通常未指定)状态:

std::vector<int> v = {2, 3, 3};
v = std::move(v); // v的值是未指定的

示例

#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
int main()
{
    std::string str = "Salut";
    std::vector<std::string> v;
    // 使用 push_back(const T&) 重载,这意味着
    // 我们将承担复制 str 的成本
    v.push_back(str);
    std::cout << "After copy, str is " << std::quoted(str) << '\n';
    // 使用右值引用 push_back(T&&) 重载,
    // 这意味着不会复制字符串;而是将 str 的
    // 内容移动至 vector 中。这样成本更低,
    // 但也意味着 str 现在可能为空
    v.push_back(std::move(str));
    std::cout << "After move, str is " << std::quoted(str) << '\n';
    std::cout << "The contents of the vector are {" << std::quoted(v[0])
              << ", " << std::quoted(v[1]) << "}\n";
}

可能的输出:

After copy, str is "Salut"
After move, str is ""
The contents of the vector are {"Salut", "Salut"}

参见

(C++11)
转发函数实参,并通过模板类型参数保持其值类别
(函数模板)
若移动构造函数不抛出异常,则将实参转换为右值引用
(函数模板)
(C++11)
将元素范围移动到新位置
(函数模板)