unique_ptr<T>不允许复制构造,相反,它支持移动语义。但是,我可以从函数返回unique_ptr<T>并将返回值赋给变量。
#include <iostream>
#include <memory>
using namespace std;
unique_ptr<int> foo()
{
unique_ptr<int> p( new int(10) );
return p; // 1
//return move( p ); // 2
}
int main()
{
unique_ptr<int> p = foo();
cout << *p << endl;
return 0;
}
上面的代码按预期进行编译和工作。那么,为什么第1行没有调用复制构造函数并导致编译器错误呢?如果我不得不使用第2行,那就有意义了(使用第2行也可以,但我们不需要这样做)。
我知道c++ 0x允许unique_ptr这个异常,因为返回值是一个临时对象,一旦函数退出就会被销毁,从而保证了返回指针的唯一性。我很好奇这是如何实现的,它在编译器中是特殊的,还是在语言规范中有一些其他的子句,这利用了?
我认为这在Scott Meyers的《Effective Modern c++》第25条中得到了完美的解释。以下是节选:
标准支持RVO的部分继续说,如果满足RVO的条件,但编译器选择不执行复制省略,则返回的对象必须被视为右值。实际上,标准要求当允许RVO时,要么发生复制省略,要么隐式应用std::move到返回的局部对象。
Here, RVO refers to return value optimization, and if the conditions for the RVO are met means returning the local object declared inside the function that you would expect to do the RVO, which is also nicely explained in item 25 of his book by referring to the standard (here the local object includes the temporary objects created by the return statement). The biggest take away from the excerpt is either copy elision takes place or std::move is implicitly applied to local objects being returned. Scott mentions in item 25 that std::move is implicitly applied when the compiler choose not to elide the copy and the programmer should not explicitly do so.
在您的例子中,代码显然是RVO的候选对象,因为它返回局部对象p,而且p的类型与返回类型相同,这将导致复制省略。如果编译器选择不省略副本,不管出于什么原因,std::move将被踢到第1行。