考虑以下功能:
Widget f(Widget w) {
return w;
}
假设Widget
实现了复制和移动构造函数,根据C ++标准,w
必须在return语句中被视为 rvalue 对象,以防万一编译器不会认为copy elision是一个更好的选择。
另一方面,请考虑以下版本:
Widget f(Widget&& w) {
return w;
}
与第一个版本相反,根据Item 25
的{{1}},作者似乎暗示返回Effective Modern C++
肯定会调用复制构造函数。换句话说,他建议改为返回w
,以使编译器使用(可能更快)移动构造函数。
你能解释一下为什么以std::move(w)
作为参数的f()
的第二个版本不等于第一个版本的第一个版本,它取值为Widget&&
相对于在{ return语句,还考虑到在两个函数的主体中,表达式Widget
指的是w
?
演示行为的完整示例:
lvalue
输出:
#include <iostream>
struct Widget
{
Widget() { std::cout << "constructed" << std::endl; }
~Widget() { std::cout << "destructed" << std::endl; }
Widget(const Widget&) { std::cout << "copy-constructed" << std::endl; }
Widget(Widget&&) { std::cout << "move-constructed" << std::endl; }
};
Widget
f1(Widget w)
{
return w;
}
Widget
f2(Widget&& w)
{
return w;
}
int
main()
{
f1(Widget {});
std::cout << std::endl;
f2(Widget {});
}
答案 0 :(得分:5)
隐式移动的标准基于何时允许复制省略,但有一些例外。对于不是函数参数或捕获参数的本地对象,允许复制省略。隐式移动会添加作为函数参数的本地对象。因此它允许在Widget f(Widget w) { return w; }
中,但不在Widget f(Widget&& w) { return w; }
中,其中w
是局部变量,但不是本地对象。
在目前不允许的情况下,隐式移动会很安全,包括在您的示例中。但是,根据具体情况仔细考虑隐含移动,并且您的示例要么尚未被考虑,要么尚未被视为安全。
非常类似示例Widget f(Widget& w) { return w; }
是不安全的:执行Widget w; f(w);
的调用者无法期望编译器清除w
。
这个非常相似的例子显示了启用隐式移动有多大的风险,以及为什么你必须拼写它,即使它看起来很明显。引用&#34;局部变量&#34;的措辞将涵盖Widget&& w
,也覆盖Widget& w
。如果隐藏的移动不安全,而不是在安全的地方错过隐式移动,则必须绝对确定仅的措辞涵盖了安全案例