凡有名者,皆为左值。——无求备叟
不知道 C++ 右值引用的读者,推荐阅读如何评价 C++11 的右值引用(Rvalue reference)特性? - Tinro的回答 - 知乎.
std::move 只是尝试把一个左值临时性地 cast 成右值,本身不发生任何移动。cast 是可能失败的,比如尝试 cast 一个 const 值,这时 move 等于啥也没干。
真正的移动发生在何时呢?发生在把一个右值使用拷贝函数或赋值操作符赋值给另一个左值的时候。
string a = "hello";
string b = move(a);
// move(a) 并没有移动,真正的移动发生在 b = move(a)
同时,值得注意的是,一个变量名本身永远是左值,所以即使你声明了一个右值引用如 string&& a,后面用到 a 的时候 a 还是左值,如果你想把 a 移动到 b,仍需要用 move 把它临时性地变成右值:b=move(a)。 注意,右值一定是没有变量名的,这个例子里只有 move(a) 才是右值,a 或者 b 都是左值。这也是为什么说 move 是一种「临时性」的右值 cast,因为右值的不可名性决定了它不可能不是临时的。
右值引用的声明一般出现在函数形参里,这样它既可以接收右值,也可以按引用接受经过 move 临时变成右值的左值。
函数形参列表里的 string && a, 正确解读应该是:接收右值,按引用传递。同理,string& 就是接收左值,按引用传递。如果没有&号那自然就是按值传递了。
注意,这里说的左值右值是针对外面传进来的那个值而言的,a 在函数内部一定是左值。「凡有名者,皆为左值」。