smart_pointer

引入:
C++程序员最痛苦的莫过于对内存管理,没有像C#和Java那样的内存回收机制,C++程序员在复杂的程序中容易造成内存泄漏,即便是程序员非常小心,异常的产生也会造成部分内存泄漏。(由于异常而导致delete语句没有释放动态分配的内存)从而引出了智能指针(smart_pointer)。
什么是智能呢?
这种指针实质是一个包装了一个指针的类,通过RAII机制来自动释放内存。下面会详细介绍RAII。通过在类里重载 * 运算符,和->运算符来实现基本指针的操作。
RAII(Resource Acqisition Is Initialzation)的缩写,也就是资源获取继初始化。是一种资源管理,避免内存泄漏的方法。RAII的做法是使用一个对象在构造时获取资源,在对象生命周期结束时自动调用析构函数来释放内存。
C++提供了基本的三种智能指针库里的(auto_ptr ,scoped_ptr)和C++11 boost库里的
shared_ptr.
下面来一一分析以下几个指针:
auto_ptr 第一代智能指针

template<class T>
class Auto_ptr
{
public:
    Auto_ptr(T*p=0)
        :_ptr(p)
    {}
    ~Auto_ptr()
    {
        delete _ptr;
        _ptr = NULL;
    }
T& operator *()
    {
    return *_ptr;
    }
T* operator->()
{
    return _ptr;
}
T operator=(T&t)
{
    *_ptr = t;
}
private:
    T *_ptr;
};
class my_struct
{
public:
    my_struct(int i=10,int j=20)
        :_i(i)
        , _j(j)
    {}
    int _i;
    int _j;
};
int main()
{
    Auto_ptr<int> p1(new int(3)); 
    Auto_ptr<my_struct> p2(new my_struct);
cout<<"*p1 = "<<*p1<<endl;
cout << "p2->_i= "<<p2->_i<<endl;
cout <<"p2->_j= "<< p2->_j<<endl;
return 0;
}

测试:
这里写图片描述

auto_ptr首先具有RAII也就是智能,也具有指针的普通操作。
但以上程序没介绍到赋值运算符重载 和拷贝构造。是因为auto_ptr的赋值运算符重载是一种管理权限转移的操作。如下图
这里写图片描述
要实现p1=p2,假设p1已经指向一块空间,那么就会让p2先指向这块空间,把p1至为空。也就是管理权限转变给了p2,这和我们的初心大相径庭。
而如果两个同时指向一块空间,析构的时候就会把原来的数据给丢失。所以auto_ptr是一个失败的例子。
scoped_ptr解决了auto_ptr的缺陷,也就是只给出了赋值运算符和拷贝构造的定义,并且为了防止恶意破坏,封装在private里。

template<class T>
class scoped_ptr
{
public:
    scoped_ptr(T*p = 0)
        :_ptr(p)
    {}
    ~scoped_ptr()
    {
        delete _ptr;
        _ptr = NULL;
    }
    T& operator *()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    scoped_ptr(scoped_ptr<T>& ptr);
    scoped_ptr<T>& operator=(scoped_ptr<T>& ptr);
    T *_ptr;
};

最后C++提出了shared_ptr在boost库里,里面运用了引用计数的管理方法进行赋值,等操作。

template<class T>
struct Delete
{
    void operator()(T* ptr)
    {
        delete ptr;
    }
};

template<class T>//定制的删除数组删除器
struct DeleteArray
{
    void operator()(T* ptr)
    {
        delete[] ptr;
    }
};

template<class T, class D = Delete<T>>
class SharedPtr
{
public:
    SharedPtr(T* ptr)
        :_ptr(ptr)
        ,_countRef(new int(1))
    {}

    SharedPtr(const SharedPtr<T, D>& sp)
        :_ptr(sp._ptr)
        ,_countRef(sp._countRef)
    {   
        ++(*_countRef);
    }

    SharedPtr<T, D>& operator=(const SharedPtr<T, D>& sp)
    {
        if(_ptr != sp._ptr)
        {
            Release();
            _ptr = sp._ptr;
            use_count = sp.use_count;
            ++(*use_count);
        }

        return *this;
    }

    inline void Release()
    {
        if (--(*_countRef) == 0)
        {
            cout<<_ptr<<endl;
            //delete _ptr;
            _del(_ptr);
            delete _countRef;
        }
    }

    ~SharedPtr()
    {
        Release();
    }

    //operator*()
    //operator->()

    int UseCount()
    {
        return *_countRef;
    }

protected:
    T* _ptr;        // 
    int* _countRef; // 引用计数

    D _del; // 定制的仿函数删除器
};

但是shared_ptr指向一个双链表节点的时候会出现循环引用,也就是这个节点的引用计数是循环的
这里写图片描述
每个节点的引用计数永远是2,产生错误。
为了解决问题 boost库里引入weak_ptr指针解决。包含头文件

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值