在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
??
答案 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值,到期值)是合理的。)
最近suggested由Richard Smith(之前由Xeo提供),我认为这是一个非常好的主意。