文章目錄
C++代碼,發現異常沒那麼簡單,使用須謹慎。
翻閱了《Effective C++》 《More Effective C++》《Inside The C++ Object Model》的相關章節,大概弄明白了一些東東,總結在本文。
本文不是總結普適的C++異常機制,還沒有這個內力哈! 主要是結合建構函式和解構函式,來總結異常對他倆的影響。建構函式和解構函式本來就很折磨腦筋,再疊加上異常機制,確實比較複雜。
異常與解構函式
本節內容較少,因此先說。建構函式放到下一節討論。
絕對不要將異常拋出解構函式
這一條在《Effective C++》 《More Effective C++》中均被作為獨立章節講解,可見其重要性。
有一點不要誤解:解構函式的代碼當然可以throw異常,只是這個異常不要被拋出解構函式之外。如果在解構函式中catch住異常,並且不再拋出,這就不會帶來問題。
至於原因,有兩點。我們先看第一點。
異常被拋出解構函式之外,往往意味著解構函式的工作沒有做完。如果解構函式需要釋放一些資源,異常可能導致資源流失,使得程式處於一個不安全的狀態。
如下面的虛擬碼所示,異常導致p不能free,從而造成記憶體泄露。
Cpp代碼
- class A
- {
- public:
- ~A()
- {
- throw exception;
- free(p);
- }
- };
OK,這個問題好辦,我好好寫代碼,確保解構函式釋放所有的資源之後,才拋出異常。這還不行嗎?
我們來看第二個原因。 如果兩個異常同時存在:第一個異常還沒有被catch,第二個異常又被拋出,這會導致C++會調用terminate函數,把程式結束掉!異常與建構函式
建構函式本來就是一件難以琢磨的東東,背後做了很多事情:成員對象的構造、基類成分的構造、虛表指標的設定等。這些事情本來就很糾結了,再讓建構函式拋出異常,會出現怎樣的悲劇呢?
有一點比較安慰:異常即使被拋出建構函式之外,也不會造成程式結束。那麼,是否存在資源泄漏的問題呢?不可一概而論,我們分情況分析。