返回声明异常

时间:2015-02-17 22:37:47

标签: c++ c++11 c++14

考虑以下功能:

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 {});
}

1 个答案:

答案 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。如果隐藏的移动不安全,而不是在安全的地方错过隐式移动,则必须绝对确定的措辞涵盖了安全案例