智能指针

要说智能指针我们应该先了解一下RAII
RAII(Resource Acquisition Is Initialization),也成为“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。C++标准保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。简单的说,RAII 的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。
智能指针就融合了RAII这种思想。

void fun()
{
    simple* mySimplePtr=new Simple();
    mySimplePtr->go();
    delete mySimplePtr;
}

如上代码,看着好着了,但是仍然可能存在内存泄露的问题,如果go()抛出异常,那么mySimplePtr便永远不会调用delete
如果我们用智能指针就不会有内存泄露。通过模拟实现auto_ptr将其写成 AutoPtr<int> mySimplePtr;mySimplePtr>go();mySimplePtrshiyong使用完了就会自己调用析构。
1.模拟实现auto_ptr–不建议使用

//独占所有权,所有权转移
#include<iostream>
using namespace std;

template<class T>

class AutoPtr
{
public:
    AutoPtr()
        :_ptr(NULL)
    {}

    AutoPtr(T* ptr)//构造函数
        :_ptr(ptr)
    {}

    AutoPtr(AutoPtr<T>& ap)//拷贝构造
    {
        _ptr=ap._ptr;
        ap._ptr=NULL;
    }

    AutoPtr<T>& operator=(AutoPtr<T>& ap)
    {
        if(this!=&ap)
        {
            delete _ptr;
            _ptr=ap._ptr;
            ap._ptr=NULL;
        }
        return *this;
    }

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

    T* operator->()
    {
        return _ptr;
    }

    ~AutoPtr()
    {
        cout<<"~AutoPtr"<<endl;
        delete _ptr;
    }

protected:
    T* _ptr;
};
void test1()
{
    int* p1=new int;
    AutoPtr<int> ap1;
    AutoPtr<int> ap2(ap1);
    ap2=ap1;
}

再来说说auto_ptr的缺点,先褒后贬!!!
auto_ptr的缺陷:只能由一个对象来管理空间当多个auto_ptr指向同一块空间时,会由于多次释放而导致崩溃。
2.scopedptr——容易实现的智能指针
scoped_ptr独占所有权,防拷贝,只要将其拷贝构造和赋值运算符重载声明为私有。
模拟实现scoped_ptr

//独占所有权,防拷贝
#include<iostream>
using namespace std;
template<class T>
class ScopedPtr
{
public:
    ScopedPtr()
        :_ptr(NULL)
    {}
    ScopedPtr(T* ptr)//构造函数
        :_ptr(ptr)
    {}
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    ~ScopedPtr()
    {
        cout<<"~ScopedPtr"<<endl;
        delete _ptr;
    }
protected:
    ScopedPtr(ScopedPtr<T>& ap);//拷贝构造
    ScopedPtr<T>& operator=(ScopedPtr<T>& ap);//赋值运算符重载
protected:
    T* _ptr;
};
void test2()
{
    ScopedPtr<int> p1;
}

3.shared_ptr–引用计数
shared_ptr避免了双重释放而引起的问题。
模拟实现shared_ptr

//共享所有权,引用计数
#include<iostream>
using namespace std;
template<class T>

class SharedPtr
{
public:

    SharedPtr()
        :_ptr(NULL)
        ,_pCount(NULL)
    {}

    SharedPtr(T* p)
        :_ptr(p._ptr)
        ,_pCount(NULL)
    {
        if (_ptr!= NULL)  
        {  
            _pCount = new int[1];  
        }  
    }

    SharedPtr(SharedPtr<T>& p)
        :_ptr(p._ptr)
        ,_pCount(p._pCount)
    {
        if(_ptr!=NULL)
        {
            ++(*_pCount);
        }
        sp._ptr=NULL;
    }

    SharedPtr<T>& operator=(SharedPtr<T>& p)
    {
        if (this != &p)  
        {  
            //没有管理空间  
            if(_pCount==NULL)
            {
                _ptr=p._ptr;
                _pCount=p._pCount;
                if(_pCount!=NULL)
                {
                    ++(*_pCount);
                }
            }

            else if(*_pCount==1)//独自管理一段空间 
            {
                delete[] _ptr;
                delete[] _pCount;

                _ptr=p._ptr;
                _pCount=p._pCount;
                if(_pCount==NULL)
                {
                    ++(*_pCount);
                }
            }
            else             //共享空间 
            {
                --(*_pCount);  

                _ptr = p._ptr;  
                _pCount = p._pCount;  
                if (_pCount != NULL)  
                    ++(*_pCount);  
            }
        }
        return *this;
    }

private:
    T* _ptr;
    int* _pCount;
};


void test3()
{
    SharedPtr<int> p1;
    SharedPtr<int> p2;
    p2=p1;
}

3.shared_ptr依然有问题,循环引用

template<typename T>  
class Base  
{  
public:  
    Base(const T& data)  
        : _data(data)  
    {  
        cout << "Base()" << endl;  
    }  

    ~Base()  
    {  
        cout << "~Base" << endl;   
    }  
    shared_ptr<Base<T>> _next;  
    shared_ptr<Base<T>> _pre;  
    T _data;  
};  
int main()
{
    //test1();
    //test2();
    //test3();
    shared_ptr<Base<int>> s1(new Node<int>(1));  
    shared_ptr<Base<int>> s2(new Node<int>(2)); 

    s1->_next = s2;  
    s2->_pre = s1;  
    return 0;
}

以上代码就会有循环引用的问题,为了解决循环引用问题提出了weak_ptr,我们要将

shared_ptr<Base<int>> s1(new Node<int>(1));  
shared_ptr<Base<int>> s2(new Node<int>(2)); 

换为

weakptr<Base<int>> s1(new Node<int>(1));  
weak_ptr<Base<int>> s2(new Node<int>(2)); 

weak_ptr可以包含由shared_ptr管理的内存的引用。但不会拥有这个内存,所以不能阻止shared_ptr释放内存。weak_ptr离开作用域时不会销毁它指向的内存;然而它可以用来判断内存是否已经被关联的shared_ptr释放了。(书上总结的)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值