【C++】智能指针

先来看一段代码:

void Test()
{
      int* p1 = new int(5);
      bool End = true;
      //DoSomething
      if(End = true//此时如果条件成立,直接return,就会造成我们前面用new开辟的空间不能释放,从而导致内存泄漏。
      {
            return;
      }
      //DoSomething
      delete p1;
}

以上存在在的问题我们可以在return之前释放空间,也可以通过下面抛异常来解决这个问题,但是尽管如此,我们有时也很难避免内存泄漏,这时就引入了智能指针。

void DoSomeThing ()
{
      //...
      throw 2 ;
      //...
}
void Test2 ()
{
      int* p1 = new int(2);
      //...
      try 
      {
         DoSomeThing();
      }
      catch(...)
      {
         delete p1 ;
         throw;
      }
     //...
     delete p1 ;
}

1:智能指针的发展历史
这里写图片描述

auto_ptr/scoped_ptr/shared_pr/weak_ptr的设计思想、缺陷
auto_ptr:

template<class T>
class  Auto_ptr
{
public:
    Auto_ptr(T* ptr=NULL)   //构造函数
        :_ptr(ptr)
    {
    }
    Auto_ptr(Auto_ptr<T>& ap)  //拷贝构造函数
        :_ptr(ap._ptr)
//当进行拷贝构造时,直接把ap._ptr赋值为NULL,将管理权交给_ptr
    {
        ap._ptr = NULL;
    }
    Auto_ptr<T>& operator=(Auto_ptr<T>& ap) //赋值运算符的重载
    {
        if (_ptr != ap._ptr) //判断是否是自己给自己赋值
        {
            if (_ptr)    //不为空直接释放-ptr
            {
                delete _ptr;
            }
            //把ap._ptr给_ptr,ap._ptr赋值为NULL,将管理权交给_ptr
            -ptr = ap._ptr;
            ap._ptr = NULL;
        }
        return *this;
    }
    ~Auto_ptr()     //析构函数
    {
        if (_ptr)
        {
            delete _ptr;
            _ptr = NULL;
        }
    }
    T* operator->()
    {
        return _ptr;
    }
    T& operator*()
    {
        return *_ptr;
    }
private:
     T* _ptr;
};

当我们进行一般简单的使用操作时并不会出现什么问题,但是,因为auto_ptr的设计思想是管理权的转移,当我们利用p1赋值或者拷贝构造给p2时,p1就会置NULL,当我们再去访问旧的指针时就会出错。
这里写图片描述
scoped_ptr:
为了解决auto_ptr拷贝构造和赋值后对旧指针操作出错问题,我们引入了scope_ptr,它的设计思想就是防拷贝,当用户需要拷贝或者赋值时,程序直接报错。我们模拟实现时,将拷贝构造和赋值运算符重载只声明不实现,并将其设为私有。

template<class T>

class Scoped_ptr
{
public:
    Scoped_ptr(T* ptr = NULL)
        :_ptr(ptr)
    {}
    ~Scoped_ptr()
    {
        if (_ptr)
        {
            delete _ptr;
            _ptr = NULL;
        }
    }
    T* operator->()
    {
        return _ptr;
    }
    T& operator*()
    {
        return *_ptr;
    }
private:
    //拷贝构造和赋值运算符重载只声明不实现,并声明为私有防止类外实现
    Scoped_ptr<T>(Scoped_ptr<T>& sp);
    Scoped_ptr<T>& operator=(Scoped_ptr<T>& sp);
    T* _ptr;
};

shared_pr:
设计思想:引用计数,多个指针指向同一块空间,

template<class T>
class Shared_ptr
{
public:
    Shared_ptr(T* ptr=NULL) //构造函数,添加引用计数
        :_ptr(ptr)
        , _refCount(new int(1))
    {}
    Shared_ptr<T>(Shared_ptr<T>& sp)
        :_ptr(sp._ptr)
        , _refCount(sp._refCount)
    {
        ++(*_refCount);
    }
    Shared_ptr<T>& operator=(Shared_ptr<T>& sp)
    {
        if (_ptr != sp._ptr)
        {
            if (--(*_refCount) == 0)
            {
                delete _ptr;
                delete _refCount;
            }
            _ptr = sp._ptr;
            _refCount = sp._refCount;
            (*_refCount)++;
        }
        return *this;
    }
    Shared_ptr<T>& operator=(Shared_ptr<T>& sp)
    {
        swap(_ptr, sp._ptr);
        swap(_refCount, sp._ptr);
        return *this;
    }
    ~Shared_ptr()
    {
        if (--(*_refCount) == 0)
        {
            delete _ptr;
            delete _refCount;
        }

    }
    T* operator->()
    {
        return _ptr;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* Getptr()
    {
        return _ptr;
    }
private:
    T* _ptr;
    int* _refCount;

};

然而,shared_ptr存在循环引用的缺陷问题:

struct ListNode
{
    Share_ptr<ListNode> _prev;
    Share_ptr<ListNode> _next;
    ListNode()
        :_prev(NULL)
        ,_next(NULL)
    {}
};
void Test()
{
    Share_ptr<ListNode> cur = new ListNode;
    Share_ptr<ListNode> next = new ListNode;
    cur->_next = next;
    next->_prev = cur;
}

运行该程序可以看到,即使退出了test函数后,由于cur和next对象互相引用,它们的引用计数都是1,不能自动释放,并且此时这两个对象再无法访问到。这就引起了内存泄漏。
一般来讲,解除这种循环引用有下面有三种可行的方法:
1、当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
2、当cur的生存期超过next的生存期的时候,next改为使用一个普通指针指向cur。
3、使用弱引用的智能指针打破这种循环引用。
虽然这三种方法都可行,但方法1和方法2都需要程序员手动控制,麻烦且容易出错。这里主要介绍一下第三种方法。
weak_ptr:解决Shared_ptr的循环引用问题,只负责管理,不负责释放

template<class T>
class Weak_ptr
{
public:
    Weak_ptr()
        :_ptr(NULL)
    {}
    Weak_ptr(const Shared_ptr<T>& sp)
        :_ptr(sp._ptr)
    {}
    T & operator*()
    {
        return *ptr;
    }
    T & operator->()
    {
        return _ptr;
    }
private:
    T* _ptr;
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值