智能指针之unique_ptr
概述
与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。同时,unique_ptr也没有类似于make_shared的标准库函数,当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针。因此初始化unique_ptr需要使用直接初始化的形式。例如:
unique_ptr<double> p(new double(3.14)); // p指向一个值为3.14的double
并且,由于一个unique_ptr“拥有”(唯一指向)其指向的对象,所以unique_ptr不支持拷贝或者赋值操作:
unique_ptr<string> p1(new string("southernEast"));
unique_ptr<string> p2(p1); // 错误:不能拷贝
unique_ptr<string> p3;
p3 = p2; // 错误:不能赋值
虽然我们不能拷贝或者赋值一个unique_ptr,但是我们能够通过使用release或reset函数来将一个非const的unique_ptr的指针所有权转移给另一个unique_ptr。例如:
unique_ptr<string> p2(p1.realease()); // 将p1的指针所有权转移给p2,release将p1置空
unique_ptr<string> p3(new string("southernEast"));
p2.reset(p3.release()); // reset释放了p2原来指向的内存,并将p3指针的所有权转移给p2
这里需要注意的是,reset函数会释放其原来指向的对象,而release函数仅仅只是返回当前保存的指针,并将当前保存的指针值置为空,不会释放其原来指向的对象(形象地说就是“放弃控制权”)。
常用操作 | 用法说明 |
---|---|
unique_ptr< T > u | 空的指向类型为T的对象的unique_ptr |
unique_ptr< T, D > u | 使用一个类型为D的可调用对象释放它的指针 |
unique_ptr< T, D > u(d) | 使用类型为D的对象d来代替delete |
u = nullptr | 释放u指向的对象,将u置为空 |
u.release() | 放弃对指针的控制权,返回指针,并将u置为空 |
u.reset() | 释放u指向的对象 |
u.reset(q) | 将u指向内置指针q |
u.reset(nullptr) | 将u置为空 |
传递unique_ptr参数和返回unique_ptr
不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr,例如从函数返回的uinque_ptr:
unique_ptr<int> clone1(int p) {
return unique_ptr<int>(new int(p)); // 正确
}
unique_ptr<int> clone2(int p) {
unique_ptr<int> ret(new int(p)); // 正确
return ret;
}
在以上两种情况下,编译器能够知道要返回的对象将要被销毁,因此编译器会对其进行一种特殊的“拷贝”。
向unique_ptr传递删除器
重载一个unique_ptr中的删除器会影响到unique_ptr类型以及如何构造该对象,我们需要在尖括号中unique_ptr指向类型之后提供一个删除器类型。在创建或reset一个这种unique_ptr类型时,必须提供一个指定类型的可调用对象来作为删除器。形式如下:
// p指向一个objT的对象,并使用一个类型为delT的对象释放objT对象
// 它会使用一个名为fcn的delT对象作为删除器
unique_ptr<objT, delT> p (new objT, fcn);