C++析构函数的使用--异常安全

本文探讨了C++中析构函数在处理异常情况下的使用,通过示例展示了如何避免资源泄露。文章指出,使用异常处理代码可能导致性能下降且不符合异常设计原则。提出了使用带有析构函数的类来更合理地管理资源,以确保在异常发生时仍能正确关闭文件。同时,文章还讨论了类赋值运算符重载时防止重复删除资源的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一个例子:
void f()
{
   FILE* __f;
   __f=fopen(“filename”,”r+”);
   if ( __f)
   {
        // file use ①
       fclose(__f); //② 关闭文件
   }
}
如果在//①file use过程中出现了错误,抛出了异常,程序就会异常回退,不会执行到②,文件也就没有关闭。解决这类问题可以使用异常处理:
void f()
{
   FILE* __f;
   __f=fopen(“filename”,”r+”);
   if(__f)
   {
      try
      {
          // file use ①
      }
      catch(...)
      {
          fclose(__f); //② 关闭文件
          throw; // 重新抛出异常
      }
      fclose(__f);//② 关闭文件
   }

}
这种方案的缺点:
1.影响性能
2.背离异常设计的原则,异常处理代码和正常的代码没有很好的分离。只不过是:
if(error)
{
   //错误处理
}
的偷懒写法。

在delphi 、java、 C#中引入了finally关键字,使这种设计方案更为流行;C#中的using只不过简化了try finally的写法。


更为合理的方案:
class file
{
   FILE* __f;
Public:
   file(char*filename,char* mode)
   {
       __f=fopen(filename,mode);
       if (!__f) throw exception("open error");// 文件打开失败,抛出异常,表示类构造失败,这样在异常回退中就不会调用析构函数
   }
  
   ~file()
   {
        fclose(__f); // 析构函数,关闭文件
   }
  
   operator FILE* ()
   {
       return __f;
   }
};

void f()
{
   file f1(“filename”,”r+”); //如果这边抛出异常,表示f1没有构造成功,就不会调用f1的析构
   //①use file
};
如果f1构造成功,不管//①use file会不会出错,f1离开它的做用域时都将调用它的析构函数。
当然真正编码中,应该使用标准库中的ifstream和ofstream类。

第二个例子:
class A{
   char* s;
   int length;
public:
   A(int n):length(n){
       s=new char[n];
   }
   A(const A&);
   A& operator=(const A& a){ //①
       if(this!=&a){
           delete[] s;
            length=a.length;
            s=new char[length]; //②
            //...
       }
   }
   ~A(){
       delete[] s;
   }
};
在①赋值运算符重载中,如果②抛出异常(bad_alloc),已经delete[] s ,但是析构函数还会再一次delete[]s 。这当然不是我们想要的。重新设计①:
A& operator=(constA& a){
    if(this!=&a){
        char* p;
        p=new char[length];
        //...
        length=a.length;
        delete[] s; // delete 操作是不会抛异常的
        s=p;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值