什么时候返回语句需要显式移动?

时间:2013-07-05 04:21:44

标签: c++ c++11 return implicit-conversion move-semantics

comment to another question Jonathan Wakely回应我的陈述:

  

您永远不需要显式移动局部变量函数返回   值。这是隐含的举动

- >

  

...永远不要说永远......如果是局部变量,你需要一个明确的移动   与返回类型的类型不同,例如std::unique_ptr<base> f() { auto p = std::make_unique<derived>(); p->foo(); return p; },但是   如果类型相同,它将在可能的情况下移动......

所以有时我们可能必须在返回时移动一个局部变量。

示例

std::unique_ptr<base> f() { 
  auto p = std::make_unique<derived>();
  p->foo(); 
  return p; 
}

很好,因为它提供了compilation error

> prog.cpp:10:14: error: cannot convert ‘p’ from type
> ‘std::unique_ptr<derived>’ to type ‘std::unique_ptr<derived>&&’

但是我想知道是否有很好的机会来检测这一点 - 而这是语言规则的限制或unique_ptr ??

1 个答案:

答案 0 :(得分:21)

<强>更新

现代编译器版本中不需要显式移动。

核心DR 1579更改了规则,以便即使类型不同,返回值也会被视为右值。 GCC 5为C ++ 11和C ++ 14实现了新规则。

原始回答:

这不是unique_ptr的限制,它是语言的限制,同样的限制适用于调用转换构造函数采用右值引用的任何return语句:

struct U { };

struct T {
  T(U&&) { }
};

T f() {
  U u;
  return u;  // error, cannot bind lvalue to U&&
}

这不会编译,因为[class.copy] / 32说:

  

当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就像对象是由右值指定一样。

这意味着return语句中的表达式只有在符合复制/移动省略(也称为NRVO)的情况下才能被视为右值,但是限制性太强,因为这意味着它只适用于类型完全一样,即使变量总是超出范围,因此始终将处理视为右值(在技术上作为x值,到期值)是合理的。)

最近suggestedRichard Smith(之前由Xeo提供),我认为这是一个非常好的主意。