一个unique_ptr“拥有”它所指向的对象。与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。
与shared_ptr不同,C++11没有类似make_shared的标准库函数返回一个unique_ptr(C++14标准中新添加了一个make_unique)。当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针上。类似shared_ptr,初始化unique_ptr必须采用直接初始化形式:
// 可以指向一个double的unique_ptr
unique_ptr<double> p1;
// p2指向一个值为12的int
unique_ptr<int> p2(new int(12));
由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作:
unique_ptr<string> p1(new string("This is a test"));
// 错误:unique_ptr不支持拷贝
unique_ptr<string> p2(p1);
unique_ptr<string> p3;
// 错误:unique_ptr不支持赋值
p3 = p2;
虽然我们不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个(非const)unique_ptr转移到另一个unique_ptr:
// 将所有权从p1(指向string "This is a test")转移给p2
unique_ptr<string> p2(p1.release());// realse将p1置为空
unique_ptr<string> p3(new string("another"));
// 将所有权从p3转移给p2
p2.reset(p3.release());// reset释放了p2原来指向的内存
release成员返回unique_ptr当前保存的指针并将其置为空。
reset成员接受一个可选的指针参数,令unique_ptr重新指向给定的指针。如果unique_ptr不为空,它原来指向的对象被释放。
也就是说release是不释放内存的,而reset是可能释放内存的。
调用release会切断unique_ptr和它原来管理的对象间的联系。release返回的指针通常被用来初始化另一个智能指针或给另一个智能指针赋值。如果我们不用另一个智能指针来保存release返回的指针,我们的程序就要自己负责资源的释放。
传递unique_ptr参数和返回unique_ptr
不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr。最常见的例子就是从函数返回一个unique_ptr:
unique_ptr<int> clone(int p)
{
// 正确:从int*创建一个unique_ptr<int>
return unique_ptr<int>(new int(p));
}
还可以返回一个局部对象的拷贝:
unique_ptr<int> clone(int p)
{
unique_ptr<int> ret(new int(p));
//...
return ret;
}
对于这两段代码,编译器都知道要返回的对象将要被销毁。在此情况下,编译器执行一种特殊的“拷贝”。
向unique_ptr传递删除器
重载一个unique_ptr中的删除器会影响到unique_ptr类型以及如何构造(或reset)该类型的对象。与重载关联容器的比较操作类似,我们必须在尖括号中unique_ptr所指向的类型之后提供删除器类型。在创建或reset一个这种unique_ptr类型的对象时,必须提供一个指定类型的可调用对象(删除器)。