智能指针的发展史

来源:互联网 发布:精灵虚拟光驱激活mac 编辑:程序博客网 时间:2024/06/05 20:25

1 .智能指针的发展史
智能指针的发展要从RAII说起,RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。
(1)C++98提出auto _Ptr,auto_Ptr的设计是让两个指针指向同一块空间,但是这样会存在释放不当,出现程序崩溃的问题。
(2)在Boost库中设计了Scoped_Ptr,Shared_Ptr,Weak_Ptr这三种只能指针
(3)C++11经过进一步改进设计出了Unique_ptr,shared_ptr,Weak_ptr 这三种智能指针,Unique_ptr与相类似。
2.auto_Ptr/Scoped_Ptr/Shared_ptr/Weak_Ptr的设计思想、缺陷,以及它们各自的模拟实现?
(1) auto_Ptr的简单实现
auto_Ptr的几点注意事项:
auto_Ptr不能共享所有权
auto_Ptr不能指向数组
auto_Ptr不能作为容器的成员
不能通过赋值操作来初始化auto_Ptr

template<class T>class auto_Ptr{public:    auto_Ptr(T* ptr)        :_ptr(ptr)    {}    // ap2(ap1)    auto_Ptr(auto_Ptr<T>& ap)        :_ptr(ap._ptr)    {        ap._ptr = NULL;    }    // ap1 = ap2    auto_Ptr<T>& operator=(auto_Ptr<T>& ap)    {        if (this != &ap)        {            if (_ptr)                delete _ptr;            _ptr = ap._ptr;            ap._ptr = NULL;        }        return *this;    }    ~auto_Ptr()    {        if (_ptr)        {               delete _ptr;        }    }    T& operator*()    {        return *_ptr;    }    T* operator->()    {        return _ptr;    }protected:    T* _ptr;    };

可以看到一个很明显的缺陷 当使用了构造函数和拷贝构造函数时,原来的智能指针就失效了,使用权交给了新的智能指针,这种方式叫做管理权转移,任何时候只能有一个对象指向那块区域,当有看、两个指针指向同一块区域时,程序会崩溃
这里写图片描述
(2)Boost阶段 Boost阶段提出Scoped_Ptr 守卫指针 防拷贝

SharedPtr的提出主要是建立在AutoPtr的基础上,为了防止赋值和拷贝构造,可以用两种方法解决, 其一:只声明不实现
其二:声明成私有,这样,编译时就不会报错。
Scoped_Ptr的模拟实现

template<class T>class Scoped_Ptr{public:    Scoped_Ptr(T* ptr)        :_ptr(ptr)    {}    ~Scoped_Ptr()    {        delete _ptr;    }    T& operator*()    {        return *_ptr;    }    T* operator->()    {        return _ptr;    }private:    Scoped_Ptr(const Scoped_Ptr<T>&);    Scoped_Ptr<T>& operator=(const Scoped_Ptr<T>&);protected:    T* _ptr;};

Shared_Ptr的 简单实现
相对 于AutoPtr,Shared _Ptr 解决了指针共享的所有权问题,Shared_Ptr引入了引用计数,可以被自由的拷贝和赋值。

template<class T, class Del>class Shared_Ptr{public:    Shared_Ptr()        :_ptr(NULL)        ,_refCount(NULL)    {}    Shared_Ptr(T* ptr = NULL, Del del)        :_ptr(ptr)        ,_refCount(new int(1))        ,_del(del)    {}    ~Shared_Ptr()    {        if (--(*_refCount) == 0)        {            cout<<"delete"<<endl;            delete _ptr;            _del(_ptr);            delete _refCount;        }    }    Shared_Ptr(const Shared_Ptr<T, Del>& sp)        :_ptr(sp._ptr)        ,_refCount(sp._refCount)    {        ++(*_refCount);    }     sp2 = sp3    Shared_Ptr<T>& operator=(const Shared_Ptr<T>& sp)    {        if (this != &s)        if(_ptr != sp._ptr)        {            if (--(*_refCount) == 0)            {                delete _ptr;                delete _refCount;            }            _ptr = sp._ptr;            _refCount = sp._refCount;            ++(*_refCount);        }        return *this;    }    int RefCount()    {        return *_refCount;    }    T& operator*()    {        return *_ptr;    }    T* operator->()    {        return _ptr;    }    T* GetPtr() const    {        return _ptr;    }protected:    T* _ptr;    int* _refCount;    Del _del;};

Shared_ptr会带来循环引用问题。Weakptr 是用来解决Shared_ptr循环引用的缺陷问题,WeakPtr是一个弱指针,weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少.
WeakPtr的模拟实现
  

template<class T>class Weak_Ptr{public:    Weak_Ptr()        :_ptr(NULL)    {}    Weak_Ptr(const Shared_Ptr<T>& sp)        :_ptr(sp.GetPtr())    {}    T& operator*()    {        return *_ptr;    }    T* operator->()    {        return _ptr;    }protected:    T* _ptr;};

虽然通过弱引用指针可以有效的解除循环引用, 但这种方式必须在程序员能预见会出现循环引用的情况下才能使用, 也可以是说这个仅仅是一种编译期的解决方案, 如果程序在运行过程中出
了循环引用, 还是会造成内存泄漏。
循环引用问题
你中有我,我中有你最后都导致双放都无法释放,最终导致内存泄漏,以双链表为例

struct ListNode{    Weak_Ptr<ListNode> _prev;    Weak_Ptr<ListNode> _next;    ~ListNode()    {        cout<<"~ListNode()"<<endl;    }};void TestCycleRef(){    Shared_Ptr<ListNode> cur = new ListNode;    Shared_Ptr<ListNode> next = new ListNode;    cur->_next = next;    next->_prev = cur;}

这里写图片描述
在这里,_next和_prev都是成员变量,第一块空间要想释放必须在第二块空间被释放之后才能释放,但由于第一块空间有一个节点指向第二块空间,所以只有第一块空间释放之后第二块空间才能释放,这样就带来了循环引用问题。

原创粉丝点击