1、VC版智能指针
上次的对其auto_ptr内部结构的实现有些问题:
(1)、赋值语句
auto_ptr<_Ty>& operator=(const auto_ptr<_Ty> &_Y){ if(this != &_Y){ if(_Ptr != _Y._Ptr){ if(_Owns) delete _Ptr; _Owns = _Y._Owns; } else if(_Y._Owns){ //这个地方上次写错了,自己考虑的不周到, //应该判断其是否为真,真的赋值,假的话,不能, _Owns = _Y._Owns; //因为此时万一是下面主函数所写的,就会发生 } //内存空间没人管理,内存泄漏!!! _Ptr = _Y.release(); } return *this; } int main(void){ int *p = new int(10); auto_ptr<int> pa(p); auto_ptr<int> pa1(pa); pa1 = pa; //上面赋值语句防的就是这种情况,担心同一空间没人管理,导致没法释放!!! }
(2)、就是VC版的在release()函数中也可以转移彻底,程序如下:
_Ty* release()const{ _Ty *tmp = _Ptr; //先保留原有空间的地址 ((auto_ptr<_Ty>*)this)->_Owns = false; ((auto_ptr<_Ty>*)this)->_Ptr = 0; //此时拥有权已经转移的便不再对原有空间的访问。 return tmp; }
上面是对自己上次写VC版auto_ptr的赋值语句的修改,上次考虑的情况不周,导致有可能发生内存泄漏!!!
2、标准的VS或Linux下的标准库
(1)、库里面的函数主要是:reset、release、get、->、 * 、析构、多个赋值 拷贝构造、
在这个里面对VC进行了改进,没有了所谓的拥有权,其转移的更彻底,消除了安全隐患。
在VS下面不存在拥有权的管理问题,而只是只有一个私有数据,
private: _Ty *_ptr; //就是这一个指针进行管理其空间;
其加上头文件 #include<memory> ,在内部就已经实现好了之间的所有的操作;
#include<iostream> #include<memory> //有这个头文件在,智能指针内部都已经实现好了对象之间的拷贝构造, using namespace std; //赋值语句,而不会造成内存空间的泄漏!!! int main(void){ int *p = new int(10); auto_ptr<int> pa(pa); auto_ptr<int> pa1 = pa; //其实现过程在头文件#include<memory>中均已实现; }
(2)、模拟的部分源码如下:
#include<iostream> using namespace std; template<class _Ty> class auto_ptr{ public: auto_ptr(_Ty *p = 0) : _ptr(p){} auto_ptr(auto_ptr &t) : _ptr(t.release()){} //此时不能加const,因为要对其原有的指向赋值为空 auto_ptr<_Ty>& operator=(auto_ptr<_Ty> &t){ if(this != &t){ reset(t.release()); //先释放自己,在设置其他的对象。 } return *this; } ~auto_ptr(){ if(_ptr){ delete _ptr; } } public: _Ty& operator*()const{ return *(get()); } _Ty* operator->()const{ return get(); } _Ty* get()const{ return (_ptr); } _Ty* release(){ //没有拥有权,但是同时也可以达到对对象的控制, _Ty *tmp = _ptr; //通过对原先的指针赋空,将其交了出去,自己 _ptr = 0; //便不再有所控制权了; return tmp;//此时释放函数彻底抛弃了拥有权。 } void reset(_Ty *p = 0){ if(p != _ptr && _ptr){ //这个判断至关重要,看是不是自己设置自己! delete _ptr; } //这是重新设置的空间 _ptr = p; } private: _Ty *_ptr; //没有转移权,直接切断联系,断了安全隐患! }; int main(void){ int *p = new int(10); auto_ptr<int> pa(p); cout<<*pa<<endl; auto_ptr<int> pa1 = pa; auto_ptr<int> pa2; pa2 = pa1; return 0; } /* int main(void){ int *p = new int(10); auto_ptr<int> pa(p); pa.reset(pa); //自己给自己设置,此时,若没有判断语句,自己把自己将干掉, 在重新赋值没有任何作用。何来后续的访问呢? pa.reset(); //此时释放自己原有空间,并且赋值为空! 上面get()函数还有其他的用法: 从智能指针中要回自己的地址, int *x = pa.get(); pa.release(); 此时,-ptr将为空,必须手动释放内存空间; delete x; } */
(3)、没有拥有权如何管理,靠释放函数把指针赋空,为了编写赋值语句,用了一种更好的方案,重新设置的方案。
在源码中还有其他的函数,是为了解决:
pa1 = auto_ptr<int>(new int(100)); //这种问题,临时对象只能是常对象,所以通过其他的方法解决const的问题。
在以后有机会会更深入的剖析,将其他函数一一弄清楚。