考虑以下功能:
Widget f(Widget w) {
return w;
}
Run Code Online (Sandbox Code Playgroud)
假设Widget
根据C++标准实现复制和移动构造函数,w
必须在return语句中将其视为rvalue对象,以防编译器不认为复制省略是更好的选择.
另一方面,请考虑以下版本:
Widget f(Widget&& w) {
return w;
}
Run Code Online (Sandbox Code Playgroud)
至于对面的第一个版本,根据Item 25
的Effective Modern C++
,笔者似乎暗示回来w
肯定会调用拷贝构造函数.换句话说,他建议返回std::move(w)
,以使编译器使用(可能更快)移动构造函数.
你能解释为什么第二版f()
采取Widget&&
的说法是不等同于第一个版本采取了Widget
按值相对于构造被称为return语句,也考虑到在两者的功能体的表达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 {});
}
Run Code Online (Sandbox Code Playgroud)
输出:
constructed
move-constructed
destructed
destructed
constructed
copy-constructed
destructed
destructed
Run Code Online (Sandbox Code Playgroud)
小智 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
默默由编译器清除出去.
这个非常相似的例子显示了启用隐式移动的风险程度,以及为什么你必须拼出它,即使它对你来说似乎很明显.措辞称为"局部变量",这将覆盖Widget&& w
,将还覆盖Widget& w
.如果隐藏的移动不安全,而不是在安全的情况下错过隐式移动,则必须绝对确定措辞仅涵盖安全案例.
归档时间: |
|
查看次数: |
296 次 |
最近记录: |