Mar*_* Ba 18 c++ return implicit-conversion move-semantics c++11
在对另一个问题的评论中, 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;
}
Run Code Online (Sandbox Code Playgroud)
很好,因为它给出了编译错误
> prog.cpp:10:14: error: cannot convert ‘p’ from type
> ‘std::unique_ptr<derived>’ to type ‘std::unique_ptr<derived>&&’
Run Code Online (Sandbox Code Playgroud)
但我想知道是否有一个很好的机会来检测这一般 - 这是这里的语言规则或unique_ptr ??
Jon*_*ely 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&&
}
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为[class.copy]/32说:
当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.
这意味着return语句中的表达式只有在符合复制/移动省略(即NRVO)的情况下才能被视为右值,但这种限制性太强,因为这意味着它只适用于类型完全相同的情况,即使变量总是超出范围,所以总是把它作为一个rvalue(在技术上作为xvalue,一个到期值)是合理的.
这是最近提出由理查德·史密斯(以前由XEO),我认为这是一个很好的主意.