智能指针
来源:互联网 发布:郭天祥51单片机书 编辑:程序博客网 时间:2024/05/16 15:41
智能指针是什么?
通常,内存是一种被现实管理的资源,这种管理主要是指对原生内存的获取和释放操作,在管理动态分配的内存的时候,最棘手的问题就是决定何时释放这些内存,所以我们引入了一个概念叫做智能指针!
智能指针被用来干什么?
简单来说,智能指针就是用于简化内存管理
对于c++而言,智能指针是一些在行为上类似于普通指针的类,因为其中有显式访问和间接访问,而且该类还封装了一些内存管理或者资源管理policy
智能指针模板,封装了两种不同的所有权模型:独占和共享
1.与直接操作的原生指针相比,使用独占模型几乎不需要耗费额外的开销。当操作动态分配的对象是,使用这种policy的指针可以用于处理异常抛出
2.使用共享模型的时候有时会导致非常复杂的对象生命周期问题。在这种情况下,我们通常建议让程序自身来处理对象的生命,也就是所,成语远不需要考虑对象的生命周期
在这里,我们对概念性的东西来具体化一下,下面我们来看看几种智能指针
AutoPtr
这是一种利用资源转移,职能管理单个空间的,那我们来看看新库(boost)中这种指针的实现吧
一.新版的AutoPtr
1.当不给出拷贝构造函数的时候
template<typename T>class AutoPtr{public: AutoPtr(T* p) //p-->本意不可被修改,但是_p是可以被修改的,所以p不能设置为const T* p :_p(p) {} /*AutoPtr(const AutoPtr<T>) {}*/ ~AutoPtr() { if (NULL != _p) { delete _p; } }private: T* _p;};void FunTest(){ int *p = new int; AutoPtr<int> ap(p); AutoPtr<int> ap1(ap);//没有创建拷贝构造函数,系统默认给一个拷贝构造,默认 //拷贝构造函数值拷贝,指向所拷贝空间内存,可能会导致到此多次析构导致崩溃 //系统所默认的拷贝构造函数和赋值运算符所做的事情是一样的,都是浅拷贝}
2.解决因多个对象指向一个空间释放多次而造成程序崩溃问题的方法
template<typename T>class AutoPtr{public: AutoPtr(T* p = NULL) :_p(p) {} AutoPtr(AutoPtr<T>& ap) :_p(ap._p) { ap._p = NULL; } ~AutoPtr() { if (NULL != _p) { delete _p; } }private: T* _p;};void FunTest(){ int *p = new int; AutoPtr<int> ap(p); AutoPtr<int> ap1(ap);//让ap去指向一个空的空间,防止ap1指向的空间被析构多次而造成导致程序崩溃 AutoPtr<int> ap2; ap2 = ap1;//ap1 和 ap2 还是指向同一段空间,造成了第一个问题,这时候只要给出赋值运算符的重载就可以了}
3.解决2中出现的问题
template<typename T>class AutoPtr{public: AutoPtr(T* p = NULL) :_p(p) {} AutoPtr(AutoPtr<T>& ap) :_p(ap._p) { ap._p = NULL; } //AutoPtr<T>& operator=(AutoPtr<T>& ap) //{ // if (this != &ap) // { // } // return *this; //}//可以,但是不太好 ap1(p),ap2(p),ap2=ap1,这样的话就无法判断 //修正 AutoPtr<T>& operator=(AutoPtr<T>& ap) { if (_p != ap._p) { if (NULL != _p) { delete _p; } _p = ap._p; ap._p = NULL; } return *this; } ~AutoPtr() { if (NULL != _p) { delete _p; } } //解引用的重载 T* operator*() { return *_p; } //显示重载 T* operator->() { return _p; } T* Get() { return _p; }private: T* _p;};void FunTest(){ int *p = new int; //AutoPtr<int> ap(p); //AutoPtr<int> ap1(ap);//让ap去指向空,防止ap1指向的空间被析构多次而造成导致程序崩溃 //AutoPtr<int> ap2; //ap2 = ap1;//利用赋值运算符的重载,让ap1指向空 ,防止ap2指向的空间被析构多次而造成程序崩溃}
二.旧版的AutoPtr
template<typename T>class AutoPtr{public: AutoPtr(T* p = NULL) :_p(p) { if (_p) { _owner = true; } } AutoPtr(AutoPtr<T>& ap) :_p = ap._p , _owner(ap._owner) { ap._owner = false; } AutoPtr<T>& operator=(AutoPtr<T>& ap) { if (_p != ap._p) { if (_owner) { delete _p; } _p = ap._p; _owner = true; ap._owner = false; } return *this; } ~AutoPtr() { if (_owner) { delete _p; } }private T* _p; bool _owner;};/*其中方法上是没有问题的,当我们能正确使用智能指针,也就是一个智能指针交给一个对象去管理,一对一的关系,就可以避免不必要的麻烦但是,上述问题可能在我们写代码的过程中存在,所以还是注意,换句话说,不要用AutoPtr*/
在不考虑非正规使用智能指针的前提下,第一种好一点,第二种用ap1拷贝构造ap2之后释放ap2
空间,那么ap1就成为了一个野指针,所以两种都不能用!!!!!!!!!!
ScopedPtr
相对于AutoPtr来说,这是一种防拷贝的智能指针,管理单个空间。主要特点是不能调用赋值运算符的重载和拷贝构造函数(既是优点也是缺点)
先面来看看他的代码实现
template<typename T>class ScopedPtr{public: ScopedPtr(T* p = NULL) :_p(p) {} ~ScopedPtr() { if (_p != NULL) { delete _p; _p = NULL; } } T* operator*() { return *_p; } T* operator->() { return _p; } T* Get() { return _p; }private: T* _p;private: ScopedPtr(ScopedStr<T>&); ScopedPtr<T>& operator=(const ScopedPtr<T>&);};void FunTest(){ ScopedPtr<int> sp(new int); /*ScopedPtr<int> sp1(sp); (拷贝构造)不行 */ /*ScopedPtr<int> sp2(new int); sp2 = sp; (赋值运算符重载)不行*/ }
ScopedArray
这是存在于boost库中,类似于标准库中的Vector,实现动态连续空间的管理
下面是它的代码实现
template<typename T>class ScopedArray{public: ScopedArray(T* p = NULL) :_p(p) {} T& operator[](size_t index) { return _p[index]; } const T& operator[](size_t index)const { return _p[index]; } ~ScopedArray() { if (NULL != _p) { delete[]_p; } } T* operator*() { return *_p; } T* operator->() { return _p; } T* Get() { return _p; }private: T* _p;private: ScopedArray(ScopedArray<T>&); ScopedArray<T>& operator=(const ScopedArray<T>&);};void FunTest(){ int i = 0; ScopedArray<int> sa(new int[10]); sa[0] = 10; sa[2] = 100; sa[5] = 1000; for (i = 0; i < 10; i++) { cout << sa[i] << endl; }}
将FunTest()函数在mian函数中调用即可
最后我们引入了一种关于具有程序计数器的智能指针SharedPtr
template<typename T>class SharedPtr{public: SharedPtr(T* p = NULL) :_p(p) , _pCount(NULL) { if (NULL != _p) _pCount = new int(1); } SharedPtr(const SharedPtr<T>& sp) :_p(sp._p) , _pCount(sp._pCount) { if (_pCount == NULL) { ; } else { ++(*_pCount); } } SharedPtr<T>& operator=(const SharedPtr<T>& sp) { if (_p != sp._p) { if (_p == NULL) { _p = sp._p; _pCount = sp._pCount; } else { if (0 == --(*_pCount)) { delete _p; delete _pCount; } _p = sp._p; _pCount = sp._pCount; } if (_pCount != NULL) { ++(*_pCount); } } return *this; } ~SharedPtr() { if (_pCount == NULL) { ; } else { if (0 == --(*_pCount)) { delete _p; delete _pCount; _p = NULL; _pCount = NULL; } } }private: T* _p; int* _pCount;};void FunTest(){ SharedPtr<int> sp(new int); SharedPtr<int> sp1(sp);}int main(){ FunTest(); system("pause"); return 0;}
还有其他几种智能指针不够了解,所以没有写出来,还需要好好看一下
关于以上的智能指针了解的还不是很全面,之后的学习中需要尽快补全!
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 智能指针
- 浅谈二分查找
- 【网络基础学习2】认识ICMP协议
- UItableview点击后的折叠效果的简单实现
- tensorflow35《TensorFlow实战》笔记-06-03 TensorFlow实现 GoogleInceptionV3 code
- ECLIPSE 链接数据库 MYSQL
- 智能指针
- 在Windows下使用webpack入门
- 策略模式
- 数状数组
- Mybatis的一级缓存和二级缓存机制
- java实验4(3)修改mysql数据库记录
- OpenCV 学习记录2 图像简单处理及调用摄像头
- 复制文件夹及内容
- php Header()用法