return语句何时需要显式移动

When is explicit move needed for a return statement?

本文关键字:移动 语句 何时需 return      更新时间:2023-10-16

在对另一个问题的评论中,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的限制??

更新:

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

Core 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说:

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

这意味着CCD_ 5语句中的表达式只有在符合复制/移动省略(又名NRVO)条件时才能被视为右值,即使变量总是超出范围,所以总是将is视为右值是合理的(从技术上讲,是一个xvalue,一个过期值。)

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