C++異常機制

異常就是運行時出現出現的不正常(沒說一樣),例如系統運行時耗盡了內存或遇到意外的非法輸入。C++的異常處理中,需要由問題檢測部分拋出一個對象給處理代碼,通過這個對象的類型和內容,兩個部分能夠就出現了什麼錯誤進行通信。C++的異常處理機制包括:

throw表達式,錯誤檢測部分使用這種表達式來說明遇到了不可處理的錯誤,可以說throw引發(raise)了異常。
try塊(try block),錯誤處理使用它來處理異常。try語句以try關鍵字開始,並以一個或者多個catch子句結束。
由標準庫所定義的一組異常類,用來在throw和catch之間傳遞有關的錯誤信息。

一個最簡單的例子:

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. void f(int a);  
  5.   
  6. int main()  
  7. {  
  8.         try  
  9.         {  
  10.                 f(0);  
  11.         }  
  12.         catch(int a) //參數是有類型的  
  13.         {  
  14.                 cout<<"handling exception "<<a<<endl;  
  15.         }  
  16.         return 0;  
  17. }  
  18.   
  19. void f(int a)  
  20. {  
  21.         if(a == 0)  
  22.                 throw 0;  
  23.         else  
  24.                 cout<<"fun() end"<<endl;  
  25. }  

 

有以下幾點需要注意的:
(1)可以拋出基本數據類型異常,如int和char等;
(2)可以拋出複雜數據類型異常,如結構體(在C++中結構體也是類)和類;
(3)在一個複雜的系統中一個try塊可能包含另一個tyr塊的函數,它的try塊又調用了含有try塊的另一個函數。拋出異常的時候,將暫停當前函數的執行,開始查找匹配的catch子句。首先檢查throw本身是否在try塊內部,如果是,檢查與該try相關的catch子句,看是否其中一是否與被拋出的對象匹配。如果找到匹配的catch,就處理異常;如果找不到,就退出當前函數(釋放當前函數的內存並撤銷局部對象),並繼續在調用函數中查找,如果找不到匹配的catch,調用函數也退出,並繼續在調用這個函數中查找。這個過程稱爲棧展開(stack unwinding),沿嵌套函數調用鏈繼續向上,直至爲異常找到一個catch子句。

棧展開期間,提早退出包含throw的函數和調用鏈中可能的其他函數。因異常而退出函數時,編譯器保證適當地撤銷局部對象。每個函數退出的時候,它的局部存儲被釋放。但是如果一個塊直接分配資源,在釋放資源前發生異常,在棧展開期間不會釋放該資源,例如一個塊可以通過調用new動態分配內存,如果該塊因異常而退出,編譯器不會刪除該指針,已分配的內存將不會釋放。

析構函數應該從不拋出異常。(這時C++ Primary上的原話,應該,但還是有可能)在爲某個異常進行棧展開的時候,析構函數如果又拋出自己的未經處理的另外一個異常,將會導致調用標準庫terminate函數,一般而言terminate函數將調用abort函數,強制從整個程序非正常退出。實踐中,因爲析構函數釋放資源,所以它不太可能拋出異常。標準庫類型都保證它們的析構函數不會引發異常。

(4)不能不處理異常,異常是足夠重要、使程序不能繼續正常執行的事件。如果找不到匹配的catch,程序就調用庫函數terminate。
(5)在查找匹配的catch期間,找到的catch不必是與異常最匹配的那個catch,相反,將選中第一個找到的可以處理該異常的catch。因此,在catch中,最特殊的catch必須最先出現。異常與catch異常說明符匹配的規則比匹配實參和形參類型的規則更嚴格,大多數轉換都不允許除下面三種:
1.允許從非const到const的轉換
2.允許從派生類到基類類型的轉換(所以catch(exception)一般都可以捕捉到標準庫異常,exception爲其他異常類基類)
3.允許將數組轉換爲指向數組類型的指針
(6)有可能單個catch不能完全處理一個異常,在進行了一些校正行動之後,catch可能確定該異常必須由函數調用鏈中更上層的函數來處理,catch可以通過重新拋出(rethrow)將異常傳遞給函數調用鏈中更上層的函數,重新拋出是後面不跟類型或表達式的一個throw:

  1. throw;  

空throw語句將重新拋出異常對象,它只能出現在catch或者從catch調用的函數中,如果在處理代碼不活動時候碰見空throw,就調用terminate函數。
(7)即使函數不能處理被拋出的異常,它可能想要在隨拋出異常退出之前執行一些動作,可以使用捕獲所有異常的catch子句,形式爲catch(...),catch(...)經常與重新拋出表達式結合使用,catch完成可作的所有局部工作,然後重新拋出異常:

  1. catch(...){  
  2.  //work to partially handle the exception  
  3.  throw;  
  4. }  

(8)下面是標準的exception類的層次(java裏面也有類似的)

參考:
C++ Primary
http://www.cnblogs.com/skyseraph/archive/2010/10/24/1859898.html
http://blog.csdn.net/tuwen/article/details/2295853

http://blog.csdn.net/ysu108/article/details/7753870
發佈了27 篇原創文章 · 獲贊 10 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章