智能指针及其解析
1.智能指针:智能指针就是智能的、自动化的管理指针所指向的动态资源的释放,并且可以如同指针一样使用。智能指针是RALL(初始化立即获取资源)思想的一种实现,其中初始化利用构造函数,之后将资源保存起来最后让析构函数自动清理。
2.引入智能指针原因:总的来说,是防止程序执行流的改变、或者人为因素造成的内存泄露问题,在此我们应该知道,影响执行流改变的常见语句有:goto,抛异常,return,break,continue等。
3.智能指针发展:
(1)最早期的auto_ptr
autoptr是一种有着严重缺陷的智能指针,缺陷在于当我们进行拷贝构造时,如果为浅拷贝时,可能会出现同一块空间释放多次的问题,如果为深拷贝也不合理,因为
指针的拷贝,本身就希望指向同一块空间;因此,在拷贝构造这里就出现了大的问题。
解决方案:管理权转移
即再解决对象赋值、拷贝构造的时候,如a=b,先将a的地址空间释放,然后将b.ptr指针赋值给a.ptr,最后将地址空间的管理权交给a.ptr,并且将 b.ptr置为NULL.所以,在此操作
之后,原来的指针将不能再使用,因此其缺点在于,一个智能指针只能指向一块内存,不能有几个指针指向同一块内存空间。
鉴于autoptr的严重缺陷,开发者又自主实现解决以上弊端的智能指针:
(2)scoped_ptr
它所采用的解决方案就是防函数,对拷贝构造函数、赋值运算符的重载声明为私有的 或者保护的,但不去实现它,即实现了防止拷贝,防止赋值的功能
虽然 表面上解决了auto_ptr的缺陷,但是没有了拷贝、赋值功能,为了不仅可以 屏蔽auot_ptr缺陷,还能拷贝、赋值,我们又提出来了一下:
(3)shared_ptr
shared_ptr可以说是比较完美的智能指针了,解决了它之前几个智能指针所存在的问题但是,它的缺陷却在于,它存在着循环引用的问题:
(4)weak_ptr
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,像旁观者那样观测资源的使用情况但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
2.引入智能指针原因:总的来说,是防止程序执行流的改变、或者人为因素造成的内存泄露问题,在此我们应该知道,影响执行流改变的常见语句有:goto,抛异常,return,break,continue等。
3.智能指针发展:
(1)最早期的auto_ptr
autoptr是一种有着严重缺陷的智能指针,缺陷在于当我们进行拷贝构造时,如果为浅拷贝时,可能会出现同一块空间释放多次的问题,如果为深拷贝也不合理,因为
指针的拷贝,本身就希望指向同一块空间;因此,在拷贝构造这里就出现了大的问题。
关于auto_ptr的模拟实现:
- template <class T>
- class AutoPtr
- {
- private:
- T* _ptr;
- public:
- AutoPtr(T* ptr)//构造函数
- :_ptr(ptr)
- {}
- ~AutoPtr()//析构函数
- {
- cout<<"~AutoPtr()//析构函数"<<endl;
- if(_ptr)
- {
- delete _ptr;
- }
- }
- //1.管理权的转移
- //问题缺陷:当一个智能指针交出对空间的管理权之后,将它置空,不能再对其解引用赋值,废掉
- AutoPtr(AutoPtr<T>& ap)//拷贝构造函数
- {
- _ptr=ap._ptr;
- ap._ptr=NULL;//退出管理
- }
- AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值操作符的重载
- {
- if(this!=&ap)
- {
- if(_ptr)
- {
- delete _ptr;
- }
- _ptr=ap._ptr;
- ap._ptr=NULL;//退出管理
- }
- return *this;
- }
- T& operator*()//重载*
- {
- return *_ptr;
- }
- T* operator->()//重载->
- {
- return _ptr;
- }
- };
即再解决对象赋值、拷贝构造的时候,如a=b,先将a的地址空间释放,然后将b.ptr指针赋值给a.ptr,最后将地址空间的管理权交给a.ptr,并且将 b.ptr置为NULL.所以,在此操作
之后,原来的指针将不能再使用,因此其缺点在于,一个智能指针只能指向一块内存,不能有几个指针指向同一块内存空间。
鉴于autoptr的严重缺陷,开发者又自主实现解决以上弊端的智能指针:
(2)scoped_ptr
它所采用的解决方案就是防函数,对拷贝构造函数、赋值运算符的重载声明为私有的 或者保护的,但不去实现它,即实现了防止拷贝,防止赋值的功能
关于scoped_ptr的模拟实现:
- template <class T>
- class ScopedPtr
- {
- protected:
- T* _ptr;
- public:
- ScopedPtr(T* ptr)//构造函数
- :_ptr(ptr)
- {}
- ~ScopedPtr()//析构函数
- {
- if(_ptr)
- {
- delete _ptr;
- }
- }
- T& operator*()//*的重载
- {
- return *_ptr;
- }
- T* operator->()//重载->
- {
- return _ptr;
- }
- //防拷贝的实现,即将拷贝构造、赋值运算符重载函数声明成私有的,并且不定义
- private:
- ScopedPtr(const ScopedPtr<T>& sp);
- ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
- };
(3)shared_ptr
它所采用的技术是引用计数思想,在对象构造时记下使用次数,到最后只有一个引用计数的时候再释放,所以依然支持拷贝构造和赋值的操作
关于shared_ptr的模拟实现:
- template <class T>
- class SharedPtr
- {
- protected:
- T* _ptr;
- int* _RefCount;
- public:
- SharedPtr(T* ptr)//构造函数
- :_ptr(ptr)
- ,_RefCount(new int(1))
- {}
- ~SharedPtr()//析构函数
- {
- if(--(*_RefCount)==0)
- {
- delete _ptr;
- delete _RefCount;
- }
- }
- SharedPtr(SharedPtr<T>& sp)//拷贝构造函数
- {
- _ptr=sp._ptr;
- _RefCount=sp._RefCount;
- ++(*_RefCount);//拷贝构造之后,this多了一个对象指向自己的空间
- }
- SharedPtr<T>& operator=(SharedPtr<T>& sp)//赋值运算符的重载
- {
- if(_ptr!=sp._ptr)
- {
- if(--(*_RefCount)==0)
- {
- delete _ptr;//转变指向之前,先检查自己原来在的那块空间是否只有自己一个人管理
- delete_RefCount;
- }
- _ptr=sp._ptr;
- ++(*_RefCount);
- }
- return *this;
- }
- T& operator*()//*的重载
- {
- return *_ptr;
- }
- T* operator->()//重载->
- {
- return _ptr;
- }
- };
关于循环引用:在使用shared_ptr时,由于节点之间的相互引用使得多个结点指向同一块空间,引用计数不为1,从而在释放空间时,p1等p2释放,p2等p1释放,从而引起的循环引用问题,造成内存泄露。
(4)weak_ptr
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,像旁观者那样观测资源的使用情况但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
引入weak_ptr弱引用指针即可解决循环引用问题。weak_ptr不会修改引用计数。
关于weak_pt的模拟实现:
- template<class T>
- class WeakPtr
- {
- WeakPtr()
- :_ptr(NULL)
- {}
- WeakPtr(const SharedPtr<T>& sp)
- :_ptr(sp._ptr)
- {}
- T& operator*()//*的重载
- {
- return *_ptr;
- }
- T* operator->()//重载->
- {
- return _ptr;
- }
- private:
- T* _ptr;
- };