19

对另一个问题的评论中, 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; 
}

很好,因为它给出了编译错误

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

但我想知道一般来说是否有很好的机会检测到这一点 -这是语言规则的限制还是unique_ptr

4

1 回答 1

22

更新:

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

核心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)的条件,则只能将其视为右值,但这限制性太大,因为这意味着它仅适用于类型完全相同的情况,即使变量总是超出范围,因此总是将 is 视为右值是合理的(从技术上讲,它是一个 xvalue,一个到期值。)

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

于 2013-07-05T07:42:02.747 回答