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

我们向系统申请资源,使用完之后必须要还给系统。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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值