智能指针

int* p = new int;//p是裸指针

因为有时忘记delete或者遇到return导致程序退出
智能指针的出现 是为了解决内存泄露,它利用了栈上的对象出了作用域就会自动析构的特点。所以它的设计思想是如果能在堆上手动开辟,然后由系统释放,那就很完美了。
智能指针的分类:

C++98的智能指针:auto_ptr
C++11的引入智能指针:scoped_ptr,unique_ptr( move )、shared_ptr、weak_ptr,废弃了auto_ptr

不带引用计数的智能指针包括:auto_ptr,unique_ptr,scoped_ptr
带引用计数的智能指针包括:shared_ptr weak_ptr

1.auto_ptr 是通过转移管理权来完成对象的拷贝与赋值
为了防止程序抛出异常或者不正常return导致程序结束但没有delete堆上的内存资源,我们使用auto_ptr让它在自己的析构函数中进行资源释放。
但是,它也存在一定的缺点:
例如,auto_ptr<A> ptr1(new A(10)); auto_ptr<A> ptr2 = ptr1;
这两行代码执行完成之后,ptr1已经不再指向A这个对象,ptr1=NULL,它的管理权已经释放,转移到了ptr2上。此时只有ptr2拥有对A对象的管理权。
假如我们进行以下操作:ptr1->fun();此时会报错,因为ptr1此时指向的是NULL,非法访问。
并且如 vector < auto_ptr> vec;
我们不能将auto_ptr类型的指针作为STL容器的元素,因为容器免不了要拷贝构造和赋值。
所以auto_ptr是一个被C++11废弃的智能指针,因为它存在中途释放,后面可能还要使用的问题。

2.unique_ptr 可以看成是auto_ptr的替代品,它是独占型的。在某一时刻,只能有一个unique_ptr指向的对象。
unique_ptr无法进行赋值和拷贝构造操作。auto_ptr可以进行赋值和拷贝,只是存在中途释放后续无法使用的问题,有时候会可能会搞得人莫名其妙。但是unique_ptr比较直接,它根本无法进行赋值和拷贝操作。如果一定要转移所有权的话,在C++11标准中,unique_ptr可以通过move函数实现赋值与拷贝操作,

unique_ptr < A > ptr1(new A(10));
unique_ptr< A > ptr2(std::move(ptr1));

以上代码和auto_ptr的效果是一样的,ptr1依然不再拥有A对象。

3.scoped_ptr 不支持管理权的转移,禁止用户进行拷贝与赋值。auto_ptr可以进行拷贝构造和赋值,只是存在问题。unique_ptr是独占型的,但可以通过move函数明确的告诉用户所有权转移了。scoped_ptr把拷贝构造函数和赋值运算符重载函数写在private下面,保证用户无法进行拷贝构造。

4.shared_ptr 可以多个智能指针同时拥有一个对象,shared_ptr的实现方式是使用引用计数
引用计数是在统计有多少个对象管理这个堆内存
引用计数的原理是,多个智能指针同时拥有一个对象,每当有一个新的引用指向对象时,引用计数就加1,每当删除一个引用,引用计数就减1,当引用计数为0时,就释放该对象占用的资源。
就比如,教室里每进来一个人,学生数就加1,每出去一个人,学生数就减1,当一直减到0时,教室里最后一个人离开后,需要关灯,相当于释放对象占用的资源。

5.weak_ptr 没有对对象的使用权,只有监控权。它不会增加和减少引用计数,也不会释放对象所占用的资源。
所以,weak_ptr一定要与shared_ptr配合使用,不能单独使用。在创建对象的时候,一定要强智能指针,不能用弱智能指针。

实现一个shared_ptr

1)资源引用计数管理类
class     CHeapManager
{
public:
    static     CHeapManager&     getInstance( )
    {
         return     heapmanager;
    }
    void    addRef( void *ptr )
    {
         vector<ResItem>::iterator     it = find(_vec.begin(),_vec.end(),ptr);
         if(it == _vec.end())//没找到,添加[没找到就不能有it->_refcount的操作]
         {
               ResItem     item(ptr);//拷贝构造一个ResItem类型的对象,尾插
               _vec.push_back(item);
               cout<<"new addr:"<<ptr<<" refcount:"<<1<<endl;
         }
         else//找到了,加1
         {
               it->_refcount++;
               cout<<"add res:"<<ptr<<" refcount:"<<it->_refcount<<endl;
         }
    }
    void delRef(void *ptr)
    {
         vector<ResItem >::iterator     it = find(_vec.begin(),_vec.end(),ptr);
         if(it != _vec.end())//找到了,减1
         {
               it->_refcount-- ;
               cout<<"del addr:"<<ptr<<" refcount:"<<it->_refcount<<endl;
         }
         //如果没有找到可以抛出异常
    }
    int     getRef(void *ptr)
    {
         vector<ResItem>::iterator     it = find(_vec.begin(),_vec.end(),ptr);
         if(it != _vec.end())
         {
               return it->_refcount;
         }
         throw "no resource";
    }
private:
    struct     ResItem//节点类型
    {
         ResItem(void *ptr=NULL):_paddr(ptr),_refcount(0)
         {
               _refcount = 1;
         }
         bool     operator==(void *ptr)
         {
               return _paddr == ptr;
         }
         void     *_paddr;//记录资源的起始地址
         int     _refcount;//引用计数
    };
    vector<ResItem>     _vec;
    CHeapManager( ){ }
    static     CHeapManager     heapmanager;
};
CHeapManager      CHeapManager : : heapmanager ;

//(2)智能指针类
template<typename  T>
class    CSmartPtr
{
public:
    CSmartPtr(T *ptr = NULL):_ptr(ptr)
    {
         if(_ptr != NULL)
             addRef();
    }
    CSmartPtr(const CSmartPtr<T> &src):_ptr(src._ptr)
    {
         if(_ptr != NULL)
             addRef();
    }
    CSmartPtr<T>& operator=(const CSmartPtr<T> &src)
    {
         if(_ptr == src)//1.先判断是否自赋值
             return *this;

         delRef();    //2.减引用计数
         if(0 == getRef())    //3.判断引用计数是否为0,为 0 则删除
             delete _ptr;
         _ptr = src._ptr;  //4.进行赋值操作
         if(_ptr != NULL)  //5.如果又有智能指针引用,则加1
             addRef();
         return *this;   //6.返回 *this
    }
    ~CSmartPtr()
    {
         delRef();
         if(getRef() == 0)
             delete _ptr;
    }
    void addRef(){_heapManager.addRef(_ptr);}
    void delRef(){_heapManager.delRef(_ptr);}
    int getRef(){return _heapManager.getRef(_ptr);}
private:
    T *_ptr;
    static CHeapManager& _heapManager;//引用计数管理类的引用计数应该是所有对象所共享的,所以为静态
};
template<typename T>
CHeapManager& CSmartPtr<T>::_heapManager = CHeapManager::getInstance();//初始化静态成员
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值