您的位置:首页 > 其它

内存管理之常用智能指针的用法和注意事项

2015-09-06 16:08 731 查看
我们向系统申请资源,使用完之后必须要还给系统。c++中最常使用的资源就是动态分配的内存,你不使用的时候一定要归还给系统,不然就会出现内存泄露。我们一般会选择去手动释放资源,delete 掉申请的内存。但是人往往就会漏掉这些东西,内存管理就会变得头疼,于是我们就引入了更高效的内存管理方法:智能指针。

原理:

我们知道在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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: