2011-08-22 48 views
13

在析構函數中檢測到它是在堆棧展開期間運行的時候,由於引發了異常而不是觸發析構函數的範圍的正常退出,C++中的一個好方法是什麼?我想知道這樣我可以創建一個類,它有一些總是在正常退出時運行的清理代碼,但在發生異常時會跳過。檢測由於異常被拋出而導致析構函數何時運行?

+0

有趣的問題!我很想說它不能完成,因爲對象並不真正知道異常處於活動狀態,它們只是在異常展開堆棧時超出範圍,就好像它們超出了其他範圍範圍。如果有什麼,你需要一些特定於平臺的「黑客」... –

+1

好奇你爲什麼要在堆棧展開期間避免清理? –

+0

@Eric Z:我曾想過將它用於自動堆棧記錄。 'Log xxx(「funcA - 」,arg1,arg2,arg3);',但是對這些函數進行測試是很乏味的。 –

回答

16

std::uncaught_exception()(在<exception>定義)會告訴你,在你的析構函數,如果它被稱爲是因爲一個例外:

class A 
{ 
public: 
    ~A() 
    { 
     if (std::uncaught_exception()) { 
      // Called because of an exception 
     } else { 
      // No exception 
     } 
    } 
}; 
+0

不錯,我從來不知道這個存在! :-) –

+0

不如您想象的那麼好 - 請參閱我的帖子中的鏈接文章。 – Simon

0

這是我能想到的一個辦法,但似乎笨拙:

{ 
    myCleanupClass unwindAction; 
    try { 
    // do some work which may throw exception. 
    } catch (...) { 
    unwindAction.disableDestructorWork(); 
    throw; 
    } 
} 
1

不要那樣做,除非你有充分的理由。堆棧展開是一種語言功能,try塊內的所有自動對象都將被強制釋放,以便它們內部的資源有機會釋放。

您想在堆棧展開期間跳過清除,這繞開了它的初衷。而且你會冒着泄漏資源的風險。

class CDBConnection 
{ 
    public: 
    CDBConnection() 
    { 
     m_db.open(); 
    } 
    ~CDBConnection() 
    { 
     if (!std::uncaught_exception()) 
     m_db.close(); 

     // if this is called during a stack unwinding, 
     // your DB connection will not be closed for sure. 
     // That's a resource leakage. 
    } 
    //.. 
    private: 
    DB m_db; 
}; 

void main() 
{ 
    //.. 
    try 
    { 
    // code that may throw 
    CDBConnection db; 
    //..   
    } 
    catch(const CDBException& exp) 
    { 
    // properly handle the exception 
    } 
} 
4

可能this文章將幫助你。本文將向您展示std :: uncaught_exception()的問題,幷包含如何處理析構函數中的異常的建議。

相關問題