返回声明异常

Mar*_*tin 9 c++ c++11 c++14

考虑以下功能:

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 25Effective 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.如果隐藏的移动不安全,而不是在安全的情况下错过隐式移动,则必须绝对确定措辞涵盖安全案例.