我正在阅读《Effective Modern C++ Item 25》,第 172 页,它有一个示例来演示,如果您想移动返回右值引用参数,则需要用 std::move(param) 包装它。由于参数本身始终是左值,如果没有 std::move(),它将被复制返回。
我不明白。如果 std::move(param) 只是将其传入的参数转换为右值引用,那么当 param 已经是右值引用时有什么区别?
就像下面的代码一样:
#include <string>
#include <iostream>
#include <utility>
template<typename T>
class TD;
class Widget {
public:
explicit Widget(const std::string& name) : name(name) {
std::cout << "Widget created with name: " << name << ".\n";
}
Widget(const Widget& w) : name(w.name) {
std::cout << "Widget " << name << " just got copied.\n";
}
Widget(Widget&& w) : name(std::move(w.name)) {
std::cout << "Widget " << name << " just got moved.\n";
}
private:
std::string name;
};
Widget passThroughMove(Widget&& w) {
// TD<decltype(w)> wType;
// TD<decltype(std::move(w))> mwType;
return std::move(w);
}
Widget passThrough(Widget&& w) {
return w;
}
int main() {
Widget w1("w1");
Widget w2("w2");
Widget wt1 = passThroughMove(std::move(w1));
Widget wt2 = passThrough(std::move(w2));
return 0;
}
它输出:
Widget created with name: w1.
Widget created with name: w2.
Widget w1 just got moved.
Widget w2 just got copied.
在 passThroughMove(Widget&& w) 中,w 的类型已经是右值引用,std::move(w) 只是再次将其转换为右值引用。如果我取消注释 TD 行,我可以看到 decltype(w) 和 decltype(std::move(w)) 都是 Widget &&:
move_parameter.cpp:27:21: error: implicit instantiation of undefined template 'TD<Widget &&>'
TD<decltype(w)> wType;
^
move_parameter.cpp:28:32: error: implicit instantiation of undefined template 'TD<Widget &&>'
TD<decltype(std::move(w))> mwType;
^
由于 w 和 std::move(w) 都是相同的右值引用类型,为什么“return std::move(w)”会移动 w,而“return w”只会复制?
编辑:感谢您的回答和评论。现在我有了更好的理解,但不确定它是否准确。所以 std::move(w) 返回一个右值引用,就像 w 本身一样。但 std::move(w) 作为函数调用,它本身就是一个右值,因此可以移动。而 w 作为一个命名变量,它本身就是一个左值,尽管它的类型是右值引用,所以它不能被移动。