C++ 智能指针(二) std::unique_ptr

C++ STL智能指针系列:

前言

上篇文章中我们提到auto_ptr,并讲解了它的不足。为了弥补这些不足,C++11提出了unique_ptr来取代auto_ptr。

std::unique_ptr

unique_ptr,翻译过来就是"唯一的指针",从字面上就很好理解。它是独享被管理对象指针所有权的智能指针,也就是说两个指针不能指向同一个资源,复制或赋值都会改变资源的所有权。下面的第三行就会报错:

unique_ptr<Object> pObj1(new Object);
unique_ptr<Object> pObj2(move(pObj1));
cout<<pObj1->num;

从上面的代码我们可以看到unique_ptr不是进行拷贝构造的,而是进行移动构造的。这也是高明之处,C++为解决STL容器内的元素必需支持可复制和可赋值,没有提供拷贝构造函数,只提供了移动构造函数。这就意味着我们无法进行左值复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值,然后问题就解决了。

此外还有unique支持数组作为元素,其析构时会自动检测出数组,并使用delete []

unique_ptr<int[]> pArrayi(new int[10]);

我们可以来看看析构的情况:

unique_ptr<Object[]> pArrayObj(new Object[10]);

输出:

Create Object
Create Object
Create Object
Create Object
Create Object
Create Object
Create Object
Create Object
Create Object
Create Object
Free Resources
Free Resources
Free Resources
Free Resources
Free Resources
Free Resources
Free Resources
Free Resources
Free Resources
Free Resources

unique_ptr用法

在容器中使用unique_ptr

刚才我们讲了为什么unique_ptr可以在STL容器中使用,现在我们来看看具体用法:

vector<unique_ptr<string>> vec;
unique_ptr<string> ps1(new string("Hello"));
unique_ptr<string> ps2(new string("World"));

vec.push_back(std::move(ps1));
vec.push_back(std::move(ps2));

我们要注意赋值时必须使用std::move方法转化为右值才可赋值:

vec[0] = move(vec[1]);	

常用成员方法

unique_ptr中的get()release()reset()方法与auto_ptr相同,此外,unique_ptr还提供了其他的一些函数。

1. operator bool()方法

operator bool():重载了bool,可以直接判断是否为空:

unique_ptr<Object> pObj(new Object);
pObj.reset();
if(pObj){
    cout<<"is not a null pointer"<<endl;
}else{
    cout<<"is a null pointer"<<endl;
}
2. swap()方法

swap()方法可以交换两个unique_ptr的托管对象:

class Object{
public:
    Object(int num):num(num){}
    ~Object(){}
public:
    int num;
};

int main(){
    unique_ptr<Object> pObj1(new Object(123));
    unique_ptr<Object> pObj2(new Object(456));
    cout<<"pointer 1: "<<pObj1->num<<endl;
    cout<<"pointer 2: "<<pObj2->num<<endl;
    pObj1.swap(pObj2);
    cout<<"pointer 1: "<<pObj1->num<<endl;
    cout<<"pointer 2: "<<pObj2->num<<endl;
}

输出内容:

pointer 1: 123
pointer 2: 456
pointer 1: 456
pointer 2: 123
3. operator*() & operator->() & operator

对于单对象,使用operator*()operator->(),方法与auto_ptr一样。对于数组版本,则使用operator[]()

unique_ptr<int[]> pObj(new int[5]);
for(int i=0;i<5;i++)
    cout<<&pObj[i]<<endl;

输出如下:

0x2041660dc00
0x2041660dc04
0x2041660dc08
0x2041660dc0c
0x2041660dc10
4. get_deleter()方法

可以获取unique_ptr的删除器:

unique_ptr<Object> pObj(new Object());
auto del = pObj.get_deleter();

此外,unique_ptr还支持自定义删除器。

自定义deleter

我们先来看看unique_ptr源代码:

template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr
{
	...
};

可以看到我们还可以传入一个deleter。自定义deleter的应用场景是假如一个对象,不是通过delete释放的,那么就需要我们使用自定义的deleter。举个例子,C语言的标准文件操作使用FILE*指针作为句柄,然后使用fclose()放资源。我们想要使用unique_ptr代理,使其在离开作用域的时候自动释放:
自定义的deleter:

class FileDeleter{
public:
    void operator()(FILE* _fp){
        if(_fp != nullptr){
            cout<<"Free resource ..."<<endl;
            fclose(_fp);
        }
    }
};

这里是重载了一下()运算符,使其成为一个伪函数。或者我们可以直接使用函数:

void FileDeleter(FILE* _fp){
    if(_fp != nullptr){
        cout<<"Free resource ..."<<endl;
        fclose(_fp);
    }
}

在某一函数中使用:

void scope(){
    unique_ptr<FILE,FileDeleter> file(fopen("test.txt","w"),FileDeleter());
    fputs("test",file.get());
}

如果是函数,注意传入是这样使用:

    unique_ptr<FILE,void (*)(FILE*)> file(fopen("test.txt","w"),FileDeleter);

然后调用函数:

int main(){
    scope();
    cout<<"Has left the scope"<<endl;
}

我们可以看到在退出作用域时就调用了FileDeleter

Free resource ...
Has left the scope
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orbitgw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值