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
出现此异常因为返回值是一个临时对象,一旦函数退出就会被销毁,从而保证了返回指针的唯一性。我很好奇这是如何实现的,是编译器中的特殊情况还是语言规范中的其他子句可以利用?
is there some other clause in the language specification that this exploits?
是的,请参阅 12.8 §34 和 §35:
When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object [...] This elision of copy/move operations, called copy elision, is permitted [...] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type [...]
When the criteria for elision of a copy operation are met and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
只是想再补充一点,按值返回应该是这里的默认选择,因为在最坏的情况下,return 语句中的命名值,即在 C++11、C++14 和 C++ 中没有省略17 被视为右值。因此,例如以下函数使用 -fno-elide-constructors
标志
进行编译
std::unique_ptr<int> get_unique() {
auto ptr = std::unique_ptr<int>{new int{2}}; // <- 1
return ptr; // <- 2, moved into the to be returned unique_ptr
}
...
auto int_uptr = get_unique(); // <- 3
在编译时设置了标志,此函数中发生了两次移动(1 和 2),然后在稍后发生了一次移动(3)。
我是一名优秀的程序员,十分优秀!