必须要注意的 C++ 动态内存资源管理(三)——智能指针

七.前言

        在前面一节,我们简单实现了三种类型资源的”指针对象”。其实在c++11的标准库中已经为我们准备了这样的指针对象——智能指针,分别是:shared_ptr , unique_ptr(取代了auto_ptr) , weak_ptr。下面我们简单来介绍一下这三类智能指针的特点和适用情况。


八.shared_ptr智能指针

        shared_ptr指针适用的就是前一节所说的第3类资源指针。
        shared_ptr是模板类,所以可以通过任意的指针类型(这里介绍使用的是动态分配的指针,但可以不是动态分配创建的,后面会介绍)来初始化。
        shared_ptr对象可以进行拷贝,赋值;当一个对象A拷贝B或者B赋值给A,其根本都是将B的资源共享给A,然后将该资源的引用次数增加;当引用该资源的最后一个shared_ptr对象销毁的时候,会自动把该资源释放掉。下面看shared_ptr的相关操作:


函数介绍
shared_ptr<T>sp(T* res)将资源res交给sp来管理,资源不使用时会自动释放。
shared_ptr<T>sp = make_spared(params)用params参数构造T类型的对象并且交给sp来管理。
pp可以作为条件判断,若p指向一个对象,则为true,否则为false。
*p对shared_ptr<T>对象解引用,得到的是由p管理的T类型对象的引用。
p->mem等价于(*p).mem
p.get()返回p中保存的T*指针
swap(p,q)交换p,q各自内部的T*指针,注意p,q类型要相同
p.swap(q)同上
p = qp,q必须都是shared_ptr指针,并且各自管理的指针类型能相互转换。此操作会递减p的引用次数,递增q的引用次数;若p的引用次数变为0,则其管理的原内存会自动释放。
shared_ptr<T>sp(q)使得sp引用q所占资源。
p.reset() , p.reset(q)放弃p对资源的引用,若为唯一引用,还会释放内存。若传有参数q,则让p引用q所占资源。
p.use_count()返回与p共享的智能指针数量;可能很慢,主要用于调试。
p.unique()若p.use_count()为1,返回true,否则返回false


我们用下面这段简单的代码来理解shared_ptr智能指针的使用:


int main()
{
    {
        //创建一个动态string初始化为"hello wold"并交付给p来管理。
        shared_ptr<string> p(new string("hello world")); 
        {
            shared_ptr<string> q(p);//用p初始化q,则该字符串增添一个使用者
            cout << p.use_count() << endl;  // >> 2
            cout << *q << endl;   // >> "hello world"
            *q = *q + "!";  //解引用修改q管理的string对象。
        }// 跳出该代码块,q生命周期结束,则该字符串使用者又只剩p一个了。
        cout << p.use_count() << endl;  // >> 1
        cout << *p << endl; >> "hello world!"
    } // 跳出该代码块,p生命周期结束,则该字符串内存被释放。
    return 0;  
}
事实上,在不是那种临界资源的情况下,我们管理内存资源大多是使用shared_ptr智能指针。而引用计数实现的有使用者保留,无使用者才释放内存似乎完美地解决了内存释放问题。然而shared_ptr也有缺陷,不过我们留到后面来讲。


九.unique_ptr智能指针

        unique_ptr指针适用的就是前一节所说的第2类资源指针。
        unique_ptr是模板类,所以可以通过任意的指针类型(这里介绍使用的是动态分配的指针,但可以不是动态分配创建的,后面会介绍)来初始化。
        unique_ptr对象不可以进行拷贝,赋值;只能通过相关函数让unique_ptr让出的支配权然后其他unique_ptr接收。这样就保证了支配权的唯一性。下面看unique_ptr的相关操作:


函数介绍
unique_ptr<T>up(T* res)将资源res交给up来管理,资源不使用时会自动释放。
pp可以作为条件判断,若p指向一个对象,则为true,否则为false。
*p对shared_ptr<T>对象解引用,得到的是由p管理的T类型对象的引用。
p->mem等价于(*p).mem。
p.get()返回p中保存的T*指针。
swap(p,q)交换p,q各自内部的T*指针,注意p,q类型要相同。
p.swap(q)同上。
p = q这是无效操作,unique_ptr不能进行赋值。
unique_ptr<T>sp(q)这是无效操作,unique_ptr不能进行拷贝。
p = nullptr释放p指向的对象,并将p置为控。
p.release()p放弃对指针的控制权,返回资源指针,并将p置为空。
p.reset(T* q)释放p指向的对象,并将p置为空,若传入参数q,则让p指向q该指针。
p.reset(q.release())释放掉p指向的对象,q将自身指向对象的控制权转移给p,然后q自身置为空。


我们用下面这段简单的代码来理解unique_ptr智能指针的使用:


int main()
{
    {
        //创建一个unique_ptr智能指针q但是目前没有管理任何内存。
        unique_ptr<string> q;
        {
            //创建一个动态string初始化为"hello wold"并交付给p来管理。
            unique_ptr<string> p(new string("hello world"));
            cout << *p << endl;   // >> "hello world"
            q.reset(p.release()); //p将支配权

        }// 跳出该代码块,p生命周期结束,则该字符串使用者又只剩p一个了。
        cout << *q << endl; //>> "hello world"
    } // 跳出该代码块,q生命周期结束,则该字符串内存被释放。
    return 0;
}
        特别的,unique_ptr智能指针还可以用于管理动态数组:


int main()
{
    //当up释放资源的时候会自动调用 delete[] 销毁其指针。
    unique_ptr<int[]> up(new int[10]);

    //指向数组的unique_ptr指针重载了[]
    for(int i = 0 ; i < 10 ; i ++) up[i] = i;

    for(int i = 0 ; i < 10 ; i ++) 
        printf("%d",up[i]);       // >> 012345679
    return 0;
}
        一般来说,我们不常用unique_ptr智能指针来管理动态内存。而是管理类似于数据库连接对象等资源。
        有时我们的资源内存不一定是通过动态分配,而且释放有时候也不仅仅是delete 指针而已。所以,我们以后在使用unique_ptr指针的时候还需要传入删除器。这个,我们后面会详细讲到。


十.weak_ptr智能指针

        weak_ptr 是一种不控制所指向对象生命期的智能指针,它指向一个由 shared_ptr 管理的对象。将一个 weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用次数。一旦最后一个指向对象的shared_ptr 被销毁,对象就会被释放;即使这个时候存在 weak_ptr 指向了该对象,对象还是会被释放。所以我们可以把 weak_ptr 看作是一种”弱引用”。


函数介绍
weak_ptr<T>wp空 weak_ptr 可以指向类型为T的对象
weak_ptr<T>wp(sp)与shared_ptr sp指向相同的对象,T必须可以转化为sp指向对象的类型。
w = pp 可以是weak_ptr或者shared_ptr。赋值后w,p共享对象。但是w不干涉对象声明周期。
w.reset()m置为空。
w.use_count()与m共享资源的shared_ptr个数。
w.expired()若w.use_count()为0,返回true,否则返回false。
w.lock()如果expired为true,返回一个空的shared_ptr;否则返回指向w对象的shared_ptr。


        正是因为weak_ptr是一种”弱引用”,所以,很有可能在使用过程中某个weak_ptr被支配的shared_ptr给销毁了;所以我们在使用weak_ptr之前需要调用w.lock()来判断weak_ptr所指向的内存是否被释放了。


基本上,智能指针的基本操作就讲到这里,下一节会介绍智能指针的删除器以及相关注意事项。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值