异常处理(二)

异常处理(二)

  我们可能会遇到这样的情况,当我们动态分配了一个对象,在释放该对象前发生了异常。根据异常处理的流程,它会将控制权转交给匹配的catch语句处理,同时自动释放局部存储的对象。此时动态分配的对象将不能得到有效的释放,造成内存泄露的问题。这也是我们通常所说的异常安全问题。举个例子来说明一下吧

void fun()
{
    int a = 10;//分部的局部对象
    string *p = new string[10];//动态分配一个数组
    //处理代码
    ...
    //这里可能发生异常
    //如果发生了异常,函数通过异常处理流程自动清理前面分配的局部对象
    ...

    delete []p;//如果发生了异常,则不会执行这条语句。造成内存泄露。
}

   异常安全意味着,即使发生了异常,程序也能正确操作,将已经分配的资源都适当地释放。那么有什么好的办法能保证异常安全呢?可以通过定义一个类来封装资源的分配和释放,保证正确的释放资源。在设计资源管理类时,主要关注构造函数和析构函数,构造函数分配资源而析构函数释放资源。当想要分配资源的时候,就定义该类类型的对象。如果不发生异常,就在获得资源的对象超出作用域的时候释放资源(当指针或引用超出作用域时不会释放指针或引用所指对象所分配的资源)。如果在创建对象之后,但在它超出作用域之前发生了异常,那么编译器会保证撤销该对象(这正是异常所应该干的事,自动撤销局部存储对象)。下面列举一个资源管理类的例子,以来说明这种情况。

class Resource{

    public:
        Resource(params p):res(allocate(p){}
          ~Resource(){ release(res);}//其他定义
    private:
       resoure_type *res;//需要管理的资源类型
       resouce_type *allocate(parms p);//分配该资源
       void release(rescouce_type *res); //释放该资源
}

  Resource类是分配资源和回收资源的类型,即管理类类型。它保存表示该资源的数据成员,通过构造函数分配资源,析构函数释放该资源。Resource类可以这样使用:

void func()
{
    Resource res(args); //分配一个resource_type对象
    //正常代码处理</span>
    ...
    //可能发生异常
    //如果发生了异常,res的析构函数将自动运行,释放所分配的resource_type对象。
    ...
} //如果没有发送异常,函数正常结束。则res对象将超出作用域,而自动调用析构函数将resource_type对象释放

   当使用Resource类的时候,它将自动释放资源。如果函数正常终止,就在Resource对象超出作用域时释放资源;如果函数因异常而提早退出,编译器就运行Resource的析构函数作为异常处理过程的一部分。 
     其实,标准库中已经有类似的管理类来帮助我们实现异常安全。那就是auto_ptr类,该类是接受一个类型形参的模板,它为动态分配的对象提供异常安全。auto_ptr类在头文件memory中定义,具体auto_ptr类的使用可以参考相关书籍。这里说明使用auto_ptr类需要注意的地方: 
1) auto_ptr只能用于管理从new返回的一个对象,它不能管理动态分配的数组。使用auto_ptr对象指向动态分配的数组会导致未定义的运          行时行为。 
2) auto_ptr类只接受指针的构造函数为explicit构造函数,所以必须使用初始化的直接形式来创建auto_ptr对象。 
       auto_ptr pi = new int(1024); //error 
       auto_ptr pi (new int(1024)); //ok 
       pi所指的由new表达式创建的对象在超出作用域时自动删除(包括正常退出或异常)。 
3) auto_ptr和内置指针对待复制和赋值有非常关键的重要区别。当复制auto_ptr对象或者将它的值赋给其他auto_ptr对象的时候,将基础对       象的所有权从原来的auto_ptr对象转递给副本,原来的auto_ptr对象重置为未绑定的状态。 
    复制(或者赋值)普通指针是复制(或赋值)地址,在复制(或赋值)之后,两个指针指向同一对象。而在复制(或赋值)auto_ptr对象      之后,原来的auto_ptr对象不指向旧的对象而指向新的对象(左边的auto_ptr对象)拥有基础对象。 
     auto_ptr ap1(new string(“hello”));//ap1绑定到基础对象 
     auto_ptr ap2(ap1); //ap1将绑定转移给ap2了,同时ap1未绑定,此时ap2绑定到基础对象 
    对于auto_ptr类来说,复制和赋值是破坏性操作,所以不能将auto_ptr对象存储在标准容器中。标准库的容器类要求在复制或赋值之后两      个对象相等,auto_ptr不满足这一要求。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值