内存管理之常用智能指针的用法和注意事项
2015-09-06 16:08
731 查看
我们向系统申请资源,使用完之后必须要还给系统。c++中最常使用的资源就是动态分配的内存,你不使用的时候一定要归还给系统,不然就会出现内存泄露。我们一般会选择去手动释放资源,delete 掉申请的内存。但是人往往就会漏掉这些东西,内存管理就会变得头疼,于是我们就引入了更高效的内存管理方法:智能指针。
把资源放入对象中,就可以依赖c++的析构函数自动调用机制,确保资源的释放。
还有一点很重要的就是智能指针实际上对象,只不过它代理了原始指针的行为,所以我们称为智能指针。
这些指针都是轻量级的对象,都是异常安全的。
为了使用这些组件,我们在头文件中要加入:
从构造函数说起,scoped_ptr的构造函数接受一个类型为T*的指针p(它是来自于new表达式动态分配的资源或者是空指针),然后创建一个scoped_ptr对象,并在内部保存指针参数p。当scoped_ptr对象的生命周期结束时,析构函数~scoped_ptr()会调用delete自动销毁指针对象,回收资源。
复制构造函数和赋值运算符重载被声明为私有,说明不能对智能指针进行复制操作。这也说明了scoped_ptr的所有权是不可转移的。
scoped_ptr重载了引用操作符*和箭头操作符->,模仿原始指针的行为,所以我们可以把scoped_ptr对象当做指针来使用。
scoped_ptr不允许拷贝和赋值,只能进行* 或->操作。
下面是实例:
scoped_array只提供了operator[]操作符,没有提供指针运算。
建议:
在需要使用动态数组的情况下,我们应该使用vector,它比scoped_array更方便。
shared_ptr与scoped_ptr区别:
shared_ptr可以被安全共享,可以拷贝,赋值,比较。
2.shared_ptr( Y * p)获得指针p的管理权,同时引用计数置为1。
3.shared_ptr(shared_ptr const & r)从另外一个shared_ptr获取指针的管理权,同时引用计数加1,结果是两个shared_ptr共享一个指针的管理权。
4.shared_ptr(auto_ptr & r) 从一个auto_ptr获得指针的管理权,同时auto_ptr自动失去管理权。
5.shared_ptr(Y * p, D d)行为类型shared_ptr( Y * p),但是参数d指定了析构时的定制删除器,而不是简单的delete。
shared_ptr 的reset()函数作用时将引用计数减1,停止对指针的共享。
shared_ptr有两个专门的函数检查引用计数。unique()在shared_ptr是指针的唯一所有者时返回true。use_count()返回当前指针的引用计数。
实例:
实例:
成员函数:
-use_count()观测引用计数。
-expired()检测是否失效。
-lock()获得一个可用的shared_ptr对象,从而操作资源。
实例:
原理:
我们知道在c++中对象在生命周期结束时会自动调用析构函数。这不正是我们想要的所谓的“智能”。于是我们的策略就是:用对象来管理资源。把资源放入对象中,就可以依赖c++的析构函数自动调用机制,确保资源的释放。
还有一点很重要的就是智能指针实际上对象,只不过它代理了原始指针的行为,所以我们称为智能指针。
分类:
智能指针有很多种,这里我们主要介绍boost.smart_ptr库中的几种智能指针:shared_ptr,weak_ptr,scoped_ptr,scoped_array,shared_array。这些指针都是轻量级的对象,都是异常安全的。
为了使用这些组件,我们在头文件中要加入:
#include <boost/smart_ptr.hpp> using namespace boost;
scoped_ptr的用法
scoped_ptr的类摘要:
template <class T> class scoped_ptr{ private: T * px; //原始指针 scoped_ptr(scoped_ptr const &); //复制构造函数 scoped_ptr & operator= (scoped_ptr const &); //赋值运算符 public: explicit scoped_ptr(T * p = 0); //构造函数 explicit scoped_ptr(std::auto_ptr<T> p); //构造函数 ~scoped_ptr(); //析构函数 void reset(T * p =0); //重置智能指针 T & operator*(); //重载指针操作符 T & operator->(); T & get() const; //获取原始指针 operator bool() const; //bool值装换 void swap(scoped_ptr & b); //交换指针 };
从构造函数说起,scoped_ptr的构造函数接受一个类型为T*的指针p(它是来自于new表达式动态分配的资源或者是空指针),然后创建一个scoped_ptr对象,并在内部保存指针参数p。当scoped_ptr对象的生命周期结束时,析构函数~scoped_ptr()会调用delete自动销毁指针对象,回收资源。
复制构造函数和赋值运算符重载被声明为私有,说明不能对智能指针进行复制操作。这也说明了scoped_ptr的所有权是不可转移的。
scoped_ptr重载了引用操作符*和箭头操作符->,模仿原始指针的行为,所以我们可以把scoped_ptr对象当做指针来使用。
scoped_ptr的用法:
scoped_ptr<string> sp (new string("text")); cout << * sp << endl; //取字符串内容 cout << sp->size() << endl; //取字符串的长度
scoped_ptr不允许拷贝和赋值,只能进行* 或->操作。
下面是实例:
#include <boost/smart_ptr.hpp> using namespace boost;
using namespace std;
class Simple{
public:
Simple(const char * file_name){
cout << "open file:" << file_name << endl;
}
~Simple(){
cout << "close file" << endl;
}
};
int main(void){
scoped_ptr<int> p (new int); //int指针的scoped_ptr
if(p){
* p = 100;
cout << * p << endl;
}
p.reset(); //置空scoped_ptr
assert(p == 0);
if(!p){ //在bool语境中测试
cout << "scoped_ptr== null" << endl;
}
scoped_ptr<Simple> fp(new Simple("test.txt"));
}
scoped_array的用法:
它和scoped_ptr很类似,只不过是scoped_array包装了new[]在堆上分配的动态数组,当然析构的时候要使用delete[]。scoped_array<int> sa (new int [100]); sa[10] = 10; *sa = 20; //错误用法
scoped_array只提供了operator[]操作符,没有提供指针运算。
建议:
在需要使用动态数组的情况下,我们应该使用vector,它比scoped_array更方便。
shared_ptr的用法:
终于来到最关键的地方,它是最常用,也是最有用的智能指针。它是引用计数型的智能指针。shared_ptr与scoped_ptr区别:
shared_ptr可以被安全共享,可以拷贝,赋值,比较。
shared_ptr有多种构造函数形式。
1.无参的 shared_ptr()创建一个持有空指针的shared_ptr。2.shared_ptr( Y * p)获得指针p的管理权,同时引用计数置为1。
3.shared_ptr(shared_ptr const & r)从另外一个shared_ptr获取指针的管理权,同时引用计数加1,结果是两个shared_ptr共享一个指针的管理权。
4.shared_ptr(auto_ptr & r) 从一个auto_ptr获得指针的管理权,同时auto_ptr自动失去管理权。
5.shared_ptr(Y * p, D d)行为类型shared_ptr( Y * p),但是参数d指定了析构时的定制删除器,而不是简单的delete。
shared_ptr 的reset()函数作用时将引用计数减1,停止对指针的共享。
shared_ptr有两个专门的函数检查引用计数。unique()在shared_ptr是指针的唯一所有者时返回true。use_count()返回当前指针的引用计数。
shared_ptr的使用:
shared_ptr<int> sp(new int(10)); assert(sp.unique()); //现在shared_ptr是指针的唯一持有者 shared_ptr<int > sp2 = sp; //调用复制构造函数 assert(sp.use_count() ==2) //引用计数为2
工厂函数的使用:
shared_ptr很好的消除了显示delete调用,但是在shared_ptr构造中还需要显示调用new,这样就导致代码不对称性(强迫症)。shared_ptr提供了一个自由的工厂函数make_shared(),来显示消除new调用。实例:
int main(void){ shared_ptr<string> sp = make_shared<string> ("make_shared"); //创建string共享指针。 shared_ptr<vector<int>> spv = make_shared<vector<int>>(10,2); //创建vector的共享指针
shared_array的使用:
它和shared_ptr类似,包装了new[]操作符在堆上分配的动态数组,为动态数组提供了一个代理。实例:
#include <boost/smart_ptr.hpp> using namespace boost;
int main(void){
int * p = new int [100];
shared_array<int> sa(p); //shared_array代理动态数组
shared_array<int> sa2 = sa; //共享所有权
sa[10] = 10; //使用operator[]访问元素
assert(sa2[0] == 10);
weak_ptr的使用:
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它像一个助手协助shared_ptr,像旁观者来观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr构造,但是weak_ptr没有共享资源,它的构造和析构不会影响引用计数的变化。成员函数:
-use_count()观测引用计数。
-expired()检测是否失效。
-lock()获得一个可用的shared_ptr对象,从而操作资源。
实例:
shared_ptr <int> sp (new int (10)); assert(sp.use_count()==1); weak_ptr<int> wp(sp); assert(wp.use_count() ==1); //weak_ptr不影响引用计数 if(! wp.expired()){ shared_ptr<int> sp2 = wp.lock(); //获得一个shared_ptr *sp2 = 100; assert(wp.use_count()==2); }
相关文章推荐
- js闭包详解
- yii CGridView 分页 初始化 js的方法
- (leetcode)Construct Binary Tree from Inorder and Postorder Traversal
- uva 818 (位运算 + 判环)
- PHP函数__autoload失效原因(与smarty有关)
- mysql相似于oracle的to_char() to_date()方法
- GEO hash 核心原理
- Android如何绘制视图,解释了为何onMeasure有时要调用多次
- asp.net 点击完按钮后刷新页面发现还会触发buttonClick事件
- 自定义UITableViewCell(registerNib: 与 registerClass: 的区别
- 24位bmp的存储方式
- javascript必知必会之prototype(转)
- maven仓库
- 利用HTML5的画布Canvas实现刮刮卡效果
- notepad++使用正则进行替换
- CSU 1640 机智的刷题方式
- AndroidManifest.xml uses-feature 详解
- 【codevs1073】家族,胡写并查集
- 数据库对象命名参考
- hadoop工程日志