C++關於構造函數 和 析構函數 能否拋出異常的討論

構造函數析構函數分別管理對象的建立和釋放,負責對象的誕生和死亡的過程。當一個對象誕生時,構造函數負責創建並初始化對象的內部環境,包括分配內存、創建內部對象和打開相關的外部資源,等等。而當對象死亡時,析構函數負責關閉資源、釋放內部的對象和已分配的內存

在對象生死攸關的地方,如果程序代碼出現問題,常常會發生內存泄漏,從而產生可能危害系統運行的孤魂野鬼。大量的事實表明,業務邏輯代碼寫得非常嚴謹的程序在運行中仍然發現存在內存泄露,大都是構造和析構部分的代碼存在問題

而許多程序員都習慣於面向對象的編程,需要時就建立一個對象,不用時就將其釋放。這樣的習慣簡化了我們的思路,正是面向對象編程思想帶來的好處。也許由於太習慣了,很多程序員都忽略了在對象生死的瞬間也可能產生異常的問題,這種現象卻值得我們去認真反思。

其實,對象生死間的異常問題是一個充滿爭議的問題。甚至不同的編程語言,在對象生死間的異常問題上也持不同的態度。

C++語言說:一個對象在出生的過程中發生異常問題,那這個對象就是一個沒有生命的怪胎。既然它不是一個完整的對象,就根本不存在析構或釋放的說法。因此,C++在執行構造函數過程中產生異常時,是不會調用對象的析構函數的,而僅僅清理和釋放產生異常前的那些C++管理的變量空間等,之後就把異常拋給程序員處理。

 

 

那麼關於析構函數中的異常又會怎樣呢?

  對象在死亡的過程中發生異常又引出一個有趣的問題,“想死死不了”或者“死了一半又不能死了”!那麼,這個對象到底是死了還是活着?這種既死又活的對象,就像量子理論中的那隻“薛定諤的貓”一樣有趣。的確存在,卻難以琢磨!

  爲此,C++根本不去糾纏這種複雜的問題,而是採用最簡單的辦法:如果析構函數拋出異常,將直接導致當前執行線程異常終止!如果是主線程中發生析構異常,程序立即退出!

  C++的這一做法是可以理解的,當代碼已經走進無法想通的死衚衕,對象只能瘋掉,從而毀滅整個程序世界!看來並非芸芸衆生纔有無法逃脫的苦海,其實運行中的程序進程也有解不開的心結!

  所以,“永遠不要在析構函數中拋出異常”成了編寫C++代碼的一條鐵律!


構造函數和析構函數中的異常

1、構造函數可以拋出異常。

2、c++標準指明析構函數不能、也不應該拋出異常。

more effective c++關於第2點提出兩點理由:

1)如果析構函數拋出異常,則異常點之後的程序不會執行,如果析構函數在異常點之後執行了某些必要的動作比如釋放某些資源,則這些動作不會執行,會造成諸如資源泄漏的問題。

2)通常異常發生時,c++的機制會調用已經構造對象的析構函數來釋放資源,此時若析構函數本身也拋出異常,則前一個異常尚未處理,又有新的異常,會造成程序崩潰的問題。

解決辦法:

1)永遠不要在析構函數拋出異常。

2)通常第一點有時候不能保證。可以採取如下的方法:

 

 
~ClassName()
{
  try{
      do_something();
  }
  catch( ){  // 這裏可以什麼都不做,只是保證catch塊的程序拋出的異常不會被扔出析構函數之外。
   }
}

小結

構造函數拋出異常後不會調用析構函數
析構函數中拋出異常時概括性總結
  (1) C++中析構函數的履行不應當拋出異常;
  (2) 假如析構函數中拋出了異常,那麼你的體系將變得非常危險,也許很長時光什麼錯誤也不會產生;但也許你的體系有時就會莫名奇妙地崩潰而退出了,而且什麼跡象也沒有,崩得你滿地找牙也很難發明問題畢竟呈現在什麼處所;
  (3) 當在某一個析構函數中會有一些可能產生異常時,那麼就必須要把這種可能產生的異常完全封裝在析構函數內部,決不能讓它拋出函數之外
  (4) 必定要切記上面這幾條總結,析構函數中拋出異常導致程序不明原因的崩潰是許多體系的致命內傷!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章