智能指针(一)
2016-09-04 15:36
429 查看
动态内存与智能指针
为什么使用智能指针
直接看代码,一目了然
引入智能指针
定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。
1.auto_ptr,这个其实是一个坑货
看代码:
虽然上面的auto_ptr解决了内存管理问题,你不用在担心什么时候去释放那个空间。但是在拷贝构造和运算符重载时,我们很尴尬。每拷贝一个对象就要释放前面的那个对象,那么我们在后面想访问前面定义那个对象岂不是会出现问题。本来是为了解决内存问题,现在又在拷贝构造出现问题。
2.scoped_ptr 防拷贝简单暴力
对比上面的auto_ptr,会出现拷贝问题,我们把拷贝构造和赋值运算符声明为private这样外面的东西就不能访问这个成员函数了。这样就是简单暴力的求解方法
3.为了解决上面问题,引入shared_ptr,在这个类里面引用引用计数,和string一样,计数拷贝次数,当拷贝计数只有一次的话,就可以析构这个东西了。
对上面问题的解释:
所以上面那个拷贝构造的时候,解决了这个问题。
在C++中,动态内存的管理是通过一对运算符来完成的。new在动态内存中为对象 分配空间并且返回一个指向该类对象的指针。delete接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。 动态内存的使用很容易出现问题,因为确保正确的时间释放内存是极其困难的。有时我们会忘记释放内存,导致内存泄漏。 为了更容易(或者说是为了安全)地使用动态内存,我们提出了智能指针。(个人人觉得智能指针特别方便,它把内存管理封装在一个类里面,而类自己就可以完成对象的销毁,省得自己去操心)
为什么使用智能指针
直接看代码,一目了然
void Test2() { int* p1 = new int(2); bool isEnd = true; //... if (isEnd) { //delete p1;//这里要小心 return; } //... delete p1; } ///////////////////////////////////////////////// void DoSomeThing() { //... throw 2; //... } void Test2() { int* p1 = new int(2); //... try { DoSomeThing(); } catch (...) { //delete p1;//抛出异常要在这里delete否则出现野指针 throw; } //... delete p1; }
引入智能指针
定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。
1.auto_ptr,这个其实是一个坑货
看代码:
template<class T> class AutoPtr { public: AutoPtr( T* ptr) :_ptr(ptr) {} AutoPtr(AutoPtr<T>& s) //里面不能用const :_ptr(s._ptr) { s._ptr = NULL; } AutoPtr& operator=(AutoPtr<T>& s) { if (s._ptr != _ptr) { delete _ptr; _ptr = s._ptr; s._ptr = NULL; } return *this; } ~AutoPtr() { if (_ptr) delete _ptr; } T& operator*() { return *_ptr; } private: T* _ptr; }; //存在问题 AutoPtr<int> ap1 = new int(1); AutoPtr<int> ap2(ap1); AutoPtr<int> ap3(ap2); *ap1 = 10;//直接崩溃了
虽然上面的auto_ptr解决了内存管理问题,你不用在担心什么时候去释放那个空间。但是在拷贝构造和运算符重载时,我们很尴尬。每拷贝一个对象就要释放前面的那个对象,那么我们在后面想访问前面定义那个对象岂不是会出现问题。本来是为了解决内存问题,现在又在拷贝构造出现问题。
2.scoped_ptr 防拷贝简单暴力
对比上面的auto_ptr,会出现拷贝问题,我们把拷贝构造和赋值运算符声明为private这样外面的东西就不能访问这个成员函数了。这样就是简单暴力的求解方法
private: ScopePtr(const ScopePtr& sp); ScopePtr<T>& operator=(const ScopePtr& sp);
3.为了解决上面问题,引入shared_ptr,在这个类里面引用引用计数,和string一样,计数拷贝次数,当拷贝计数只有一次的话,就可以析构这个东西了。
template <class T> class SharePtr { public: SharePtr( T* ptr) :_ptr(ptr) , _pCount(new int(1)) {} ~SharePtr() { if (--(*_pCount) == 0) { delete _pCount; delete _ptr; } } SharePtr(SharePtr<T>& s) :_ptr(s._ptr) , _pCount(s._pCount) { ++*_pCount; } SharePtr<T>& operator=(SharePtr<T>& s) { if (this != &s) { if ( --(*_pCount) == 0 )//这里解决了一个问题,在下面说 { delete _ptr; delete _pCount; } _ptr = s._ptr; _pCount = s._pCount; ++(*_pCount); } return *this; } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: int *_pCount; T *_ptr; }; 用test来测试上面代码 void Test() { SharePtr<int> s1 = new int(10); SharePtr<int> s2(s1); SharePtr<int> s3 = new int(20); s2 = s3;//这块很容易出问题 }
对上面问题的解释:
所以上面那个拷贝构造的时候,解决了这个问题。
相关文章推荐
- java学习日记_16:面向对象之匿名对象。07.03
- poj1236(强连通分量)
- USB device stack
- 模式识别之统计判决
- 6.CControlUI的大小及位置
- 7_11_A题 Lights Against Dudely [HDU 4770] (状态压缩+暴力)
- 白噪声、 带限白噪声、色噪声之间的相同与差异
- Hadoop/Spark平台搭建
- open Session In View和过滤器配置
- 输入三个整数x,y,z,请把这三个数由小到大输出。
- Codeforces Round #367 (Div. 2) A
- MAC帧与PPP帧的区别
- PowerDesigner16.5使用总结
- 【模板】两多边形交并面积模板
- mybatis批量更新 使用动态表和字段
- linux0.11 bootsect.s 分析
- 竞赛真理_rqnoj160_dfs||dp
- TestWindowClose匿名内部类实现Adapter
- 惠普打印机换硒鼓(墨盒)
- ssh-keygen免密登录