析构函数中的异常

时间:2010-10-14 14:40:29

标签: c++

在我的析构函数中,我必须清理一些资源。假设我有三次调用以清除可能抛出的资源。因为让异常离开析构函数不好,我的设计模式应该是什么?显然,下面的方式不可扩展。

感谢。

class B::~B(){

try{
   clearResourceA()
 }
 catch{
     try{
         clearResourceB();
        } 
     catch{
         clearResourceC();
     }
     clearResourceC();
 }
clearResourceB();
    .
    .
}

6 个答案:

答案 0 :(得分:10)

为什么不:

try{clearResourceA();} catch(...){}
try{clearResourceB();} catch(...){}
try{clearResourceC();} catch(...){}

答案 1 :(得分:5)

将每个资源封装在一个类中,该类在其析构函数中清除它们(使用周围的try / catch):

struct ProperlyManagedA {
    // some means of using the resource - a rudimentary way is this:
    A &getA() { return a; }
    const A &getA() const { return a; }
    // cleanup
    ~ProperlyManagedA() { 
        try {
            a.clear(); // whatever it is ClearResourceA actually does
        } catch (...) {}
    }
  private:
    A a;
}

带有自定义删除器的shared_ptr是实现此目的的一种方法,无需为每种类型的资源创建整个类。

根据丢弃的内容,您可以改进以丢弃异常(例如记录问题)。

更好的是,修改资源A,B和C,以便他们在自己的析构函数中清除自己。但这可能是不可能的。

无论哪种方式,您都可以根据需要将尽可能多的此类资源放在一个类中,而无需向类的析构函数添加任何代码。这是“可扩展性”。 RAII的重点是,资源的每个用户都不必编写清理代码才能正确使用资源。

答案 2 :(得分:2)

使用catch-all(即catch(...))捕获任何可以抛出析构函数的东西,并尽力处理抛出的异常。确保没有异常从析构函数中传播出来,catch-all将帮助您防止。

答案 3 :(得分:2)

您还可以包装ClearResources函数以确保它们永远不会抛出。他们为什么还要扔?

答案 4 :(得分:1)

因为您询问了设计模式我将告诉我成功使用的经验法则。 所有具有清理/终止功能的功能都应从不抛出。

这些功能通常是公认的名称:

  • 清除*()
  • 清洁*()
  • 终止*()
  • 摧毁*()
  • 推出*()
  • 分离*()
  • 免*()
  • 擦除*()
  • 〜析构函数()
  • ...

这背后的理由是:

  • 每个资源必须至少有一个功能保证特定资源被清除
  • (递归地)如果您构建清理功能并释放多个资源,那么只使用保证这些资源将以异常安全方式发布的功能
  • 使用您的代码的程序员必须有办法清理资源
  • 如果您在库外导出清理函数,则不要传播异常(因为库的用户不知道资源是否已释放)

我可以尝试使用RAII pattern。但即使在这种情况下,上述规则也将被使用。

答案 5 :(得分:0)

try   
{  
   ClearResourceA();  
}  
catch(...)  
{  
   ExceptionWasThrown();  
}  
try   
{  
   ClearResourceB();   
}  
catch(...)  
{  
   ExceptionWasThrown();  
}  
...