c++智能指针

  • 智能指针是什么
智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。
智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放
  • 智能指针产生背景

case 1

  1 void test1(string &str)
  2 {
  3     string *ps = new string(str);
  4     ...
  5     return;
  6 }

如上边例子,我们很可能忘记delete,这将导致内存泄漏

case 2

  1 void test1(string &str)
  2 {
  3     string *ps = new string(str);
  4     delete ps;
  5     return;
  6 }

如上述例子,即便我们总是记得delete 指针,上述指针虽然被释放,但是已然变成一个野指针

case 3

  1 void test1(string &str)
  2 {
  3     string *ps = new string(str);
  4     if(weird_thing())
  5     {
  6         throw_exception();
  7     }
  8     delete ps;
  9     ps = nullptr
 10     return;
 11 }

出现异常的时候,delete将不被执行,因此导致内存泄漏
因此我们使用智能指针最少可以帮我们解决上述问题

1:智能指针能够帮助我们处理资源泄露问题
2:它也能够帮我们处理空悬指针的问题
3:它还能够帮我们处理比较隐晦的由异常造成的资源泄露
  • 智能指针
 shared_ptr:共享型智能指针
 unique_ptr、auto_ptr(已经被抛弃):独占型智能指针
 weak_ptr:观察型智能指针
  • 使用

shared_ptr

shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁.

  9 int main()
  8 {
  7     int a = 10;
  6     shared_ptr<int> pstr = make_shared<int>(a);
  5     shared_ptr<int> pstr2(pstr);
  4     shared_ptr<int> pstr3;
  3     pstr3 = pstr;
  2     cout<<"pstr's count:"<<pstr.use_count()<<endl;
  1     int *p = pstr.get();
 14      cout<<"value is:"<<*p<<endl;
  1 }

注意避免循环引用,循环引用会导致堆内存无法正确释放,导致内存泄漏。借用weak_ptr解决循环引用问题

auto_ptr

auto_ptr:独占型智能指针,同一时刻只能有一个指向给定对象,不安全

 12 int main()
 11 {
 10     auto_ptr<int> nums[3]= { 
             auto_ptr<int> (new int(1)),
             auto_ptr<int> (new int(2)),
             auto_ptr<int> (new int(3))
             };
  9
  8     auto_ptr<int> ptmp;
  7     ptmp = nums[1];
  6
  5     for(int i = 0;i < 3;++i)
  4     {
  3         cout<<"nums:"<<*nums[i]<<" ";
  2     }
  1     cout<<endl;
29  }

程序崩溃,因为ptmp = nums[1];将所有权从nums[1]转让给ptmp,这导致nums[1]不再引用该指针,在auto_ptr放弃所有权后,便可能使用他来访问该对象,当程序打印的时候,发现这是一个空指针,故崩溃
如果使用shared_ptr代替auto_ptr则ptmp和nums[1]指向同一个对象,引用计数由变为2,程序正常运行

shared_ptr<int> ptmp;
ptmp = nums[1];

如果使用unique_ptr呢?编译都无法通过。

unique_ptr

unique_ptr独占型智能指针,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。相比与原始指针unique_ptr用于其RAII的特性,使得在出现异常的情况下,动态资源能得到释放。
unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作。
unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权

     int main()
     {
         unique_ptr<int> nums[3]= 
            { 
                unique_ptr<int> (new int(1)),
                unique_ptr<int> (new int(2)),
                unique_ptr<int> (new int(3))
            };

         unique_ptr<int> ptmp;
         ptmp = nums[1];

         for(int i = 0;i < 3;++i)
         {
             cout<<"nums:"<<*nums[i]<<" ";
         }
         cout<<endl;
     }

这里写图片描述
编译都无法通过,如果非要使用,可以使用库函数move,将原有的拥有权放弃,同样,原有的拥有权放弃之后,就变成一个空指针,打印时,已然程序奔溃

程序试图将一个unique_ptr赋给另一个时,如果愿unique_ptr是个临时的右值,编译器允许这样做,因为临时对象转让拥有权之后就会被销毁,如果,原unique_ptr将存在一段时间,编译器将禁止这样做

unique_ptr<string> p1;
p1=unique_ptr<string>(new string("aa"));  (成功)

unique_ptr<string> p2;
p2=p1     (失败)

auto_ptr/shared_ptr使用new/delete 而非new[]/delete[] ,但unique_ptr有使用new[]/delete[]的版本

unique_ptr<int[]> pa(new int(10)) 

weak_ptr

weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。
weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。

int main()
 13 {
 12     int a = 10;
 11     shared_ptr<int> psh = make_shared<int>(a);
 10     cout << psh.use_count() << endl;
  9
  8     weak_ptr<int> pwp(psh);
  7     cout << pwp.use_count() << endl;
  6
  5     if(!pwp.expired())
  4     {
  3         shared_ptr<int> psh2 = pwp.lock();
  2         *psh = 100;
  1         cout << pwp.use_count() << endl;
19      }
  1 }
  • 实现一个智能指针
template<typename T>
class smartPtr
{
    private:
        T *ptr;
        int refcnt;
    public:
        smartPtr(T *p)
        {
            cout<<"constructor"<<endl;
            if(p!=nullptr)
            {
                ptr = p;
                refcnt+=1;
            }
        }
         ~smartPtr()
         {
             cout<<"destructor"<<endl;
             --refcnt;
             if(refcnt == 0)
             {
                 delete ptr;
                 ptr = nullptr;
             }
         }

         smartPtr(const smartPtr<T> &rhs)
         {
             cout<<"copy constructor"<<endl;
             if(ptr == rhs.ptr)
             {
                 refcnt = rhs.refcnt;
                 ++refcnt;
             }
         }

         smartPtr& operator=(const smartPtr<T> &rhs)
         {
             cout<<"operator = constructor"<<endl;
             if(ptr == rhs.ptr)
             {
                return *this;
             }

             --refcnt;
             if(refcnt == 0)
             {
                 delete ptr;
                 ptr= nullptr;

             }
             ptr = rhs.ptr;
             refcnt = rhs.refcnt;
             ++refcnt;
             return *this;
         }

         int getcnt()
         {
             return refcnt;
         }

         T &operator*()
         {
             return *ptr;
         }

         T &operator->()
         {
             return ptr;
         }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值