【C++】智能指针简述(二):auto_ptr
2017-03-31 21:26
337 查看
首先,我要声明auto_ptr是一个坑!auto_ptr是一个坑!auto_ptr是一个坑!重要的事情说三遍!!!
通过上文,我们知道智能指针通过对象管理指针,在构造对象时完成资源的分配及初始化,在析构对象时完成资源的清理及汕尾工作.
因此,可以得到一份简洁版的智能指针代码:
大致一看,没毛病!突然觉得自己无所不能,感觉自己就是传说中的编程天才!
可是,如果我想这样的话.....:
ap1与ap3共同管理一块空间;ap2与ap4共同管理一块空间,看起来好像没什么问题.
但当程序跑起来,出了函数作用域之后....崩毁了!!?
......Why?
好在我经验丰富,见多识广,脑袋回路中很自然地想起了类似的情况:string类的浅拷贝....
因此,机智的我立刻发现了原因:由于没有定义拷贝构造函数与赋值运算符重载,那么在拷贝构造对象和给对象赋值时,系统会默认生成相应函数.
ap1与ap3共同管理一块空间,一旦出了函数作用域,ap3会调用析构函数,delete掉所指向的空间;
而当ap1调用析构函数时,此时ap1所指向的已经是一块非法内存(因为被ap3 delete过了),因此当ap1再次delete这块空间时,程序挂掉了!
简而言之:同样一块空间被delete了两次,所以最终程序挂掉了!
那么我就好奇了,auto_ptr如何应对拷贝与赋值的呢?
在百度了各种资料及阅读其源代码之后,发现auto_ptr是这么处理的:
这是我简化后的代码,再次应对上述情况时:
我们发现:auto_ptr通过转移管理权,来保证在赋值与拷贝时仅管理一份指针,而防止同一块空间释放多次的问题.
最后,我将自己写的简洁、精简、易读的AutoPtr与库中的代码一起贴上来
库内实现(我就懒得写注释了,看完精简版后,再看库中实现会发现库内的封装性、代码复用性更高一些)
与君共勉!
通过上文,我们知道智能指针通过对象管理指针,在构造对象时完成资源的分配及初始化,在析构对象时完成资源的清理及汕尾工作.
因此,可以得到一份简洁版的智能指针代码:
template<typename T> class AutoPtr{ public: //构造函数,完成资源的初始化与分配 AutoPtr(T * ptr = NULL) :_ptr(ptr){} //析构函数,完成资源的清理及汕尾工作 ~AutoPtr(){ if(_ptr!=NULL){ delete _ptr; _ptr = NULL; } } private: T *_ptr; };
大致一看,没毛病!突然觉得自己无所不能,感觉自己就是传说中的编程天才!
可是,如果我想这样的话.....:
AutoPtr<int> ap1(new int(100)); AutoPtr<int> ap2(new int(200)); AutoPtr<int> ap3(ap1); AutoPtr<int> ap4(); ap4 = ap2;
ap1与ap3共同管理一块空间;ap2与ap4共同管理一块空间,看起来好像没什么问题.
但当程序跑起来,出了函数作用域之后....崩毁了!!?
......Why?
好在我经验丰富,见多识广,脑袋回路中很自然地想起了类似的情况:string类的浅拷贝....
因此,机智的我立刻发现了原因:由于没有定义拷贝构造函数与赋值运算符重载,那么在拷贝构造对象和给对象赋值时,系统会默认生成相应函数.
ap1与ap3共同管理一块空间,一旦出了函数作用域,ap3会调用析构函数,delete掉所指向的空间;
而当ap1调用析构函数时,此时ap1所指向的已经是一块非法内存(因为被ap3 delete过了),因此当ap1再次delete这块空间时,程序挂掉了!
简而言之:同样一块空间被delete了两次,所以最终程序挂掉了!
那么我就好奇了,auto_ptr如何应对拷贝与赋值的呢?
在百度了各种资料及阅读其源代码之后,发现auto_ptr是这么处理的:
//拷贝构造 AutoPtr(AutoPtr& ap){ //转移管理权 _ptr = ap._ptr; ap._ptr = NULL; } //赋值运算符重载 AutoPtr &operator=(AutoPtr &ap){ if(ap._ptr != _ptr){ AutoPtr tmp(ap); std::swap(_ptr,tmp._ptr); }//由析构函数去管理tmp return *this; }
这是我简化后的代码,再次应对上述情况时:
AutoPtr<int> ap1(new int(100)); AutoPtr<int> ap2(new int(200)); AutoPtr<int> ap3(ap1); //ap3 = NULL AutoPtr<int> ap4(); ap4 = ap2; //ap2 = NULL
我们发现:auto_ptr通过转移管理权,来保证在赋值与拷贝时仅管理一份指针,而防止同一块空间释放多次的问题.
最后,我将自己写的简洁、精简、易读的AutoPtr与库中的代码一起贴上来
/*
*文件说明:智能指针之AutoPtr
*作者:高小调
*日期:2017-03-30
*集成开发环境:Microsoft Visual Studio 2010
*Github:https://github.com/gaoxiaodiao/c_cplusplus/blob/master/SmartPointer/AutoPtr.h
*/
#pragma once
template<typename T>
class AutoPtr{
public:
//构造函数
AutoPtr(T * ptr = NULL)
:_ptr(ptr){}
//拷贝构造 AutoPtr(AutoPtr& ap){ //转移管理权 _ptr = ap._ptr; ap._ptr = NULL; } //赋值运算符重载 AutoPtr &operator=(AutoPtr &ap){ if(ap._ptr != _ptr){ AutoPtr tmp(ap); std::swap(_ptr,tmp._ptr); }//由析构函数去管理tmp return *this; }//析构函数
~AutoPtr(){
if(_ptr!=NULL){
delete _ptr;
_ptr = NULL;
}
}
private:
T *_ptr;
};
void TestAutoPtr(){
AutoPtr<int> ap1(new int(100));
AutoPtr<int> ap2(new int(200));
AutoPtr<int> ap3(ap1);
AutoPtr<int> ap4(ap2);
ap3 = ap4;
}
库内实现(我就懒得写注释了,看完精简版后,再看库中实现会发现库内的封装性、代码复用性更高一些)
template<class T> class auto_ptr { private: T*ap; public: //constructor & destructor-----------------------------------(1) explicit auto_ptr(T*ptr=0)throw():ap(ptr) { } ~auto_ptr()throw() { delete ap; } //Copy & assignment--------------------------------------------(2) auto_ptr(auto_ptr& rhs)throw():ap(rhs.release()) { } template<class Y> auto_ptr(auto_ptr<Y>&rhs)throw():ap(rhs.release()) { } auto_ptr& operator=(auto_ptr&rhs)throw() { reset(rhs.release()); return *this; } template<class Y> auto_ptr& operator=(auto_ptr<Y>&rhs)throw() { reset(rhs.release()); return *this; } //Dereference----------------------------------------------------(3) T& operator*()const throw() { return *ap; } T* operator->()const throw() { return ap; } //Helper functions------------------------------------------------(4) //value access T* get()const throw() { return ap; } //release owner ship T* release()throw() { T*tmp(ap); ap=0; return tmp; } //reset value void reset(T*ptr=0)throw() { if(ap!=ptr) { deleteap; ap=ptr; } } //Special conversions-----------------------------------------------(5) template<class Y> struct auto_ptr_ref { Y*yp; auto_ptr_ref(Y*rhs):yp(rhs){} }; auto_ptr(auto_ptr_ref<T>rhs)throw():ap(rhs.yp) { } auto_ptr& operator=(auto_ptr_ref<T>rhs)throw() { reset(rhs.yp); return*this; } template<class Y> operator auto_ptr_ref<Y>()throw() { returnauto_ptr_ref<Y>(release()); } template<class Y> operator auto_ptr<Y>()throw() { returnauto_ptr<Y>(release()); } };
与君共勉!
相关文章推荐
- [C/C++标准库]_[初级]_[使用auto_ptr智能指针]
- 浅谈C++的智能指针(auto_ptr)
- C++ 智能指针auto_ptr
- 【C++】智能指针 auto_ptr
- C++ - 智能指针 Vs. auto_ptr
- C++智能指针:auto_ptr、shared_ptr、weak_ptr等
- C++ auto_ptr 智能指针
- [转载]C++的智能指针auto_ptr做了些什么
- c++ stl auto_ptr智能指针
- C++学习之智能指针--auto_ptr、scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr
- 探究c++智能指针中auto_ptr_ref的存在意义
- 智能指针 auto_ptr(C++ Primier-8)
- C++ auto_ptr智能指针的用法
- 以对象管理资源——C++智能指针auto_ptr简介
- C++智能指针auto_ptr
- C++ auto_ptr 智能指针的用法
- 以对象管理资源——C++智能指针auto_ptr简介
- [C++][STL]智能指针:auto_ptr
- C++ 智能指针Auto_PTR 分析
- C++ 中的auto_ptr智能指针