c++異常處理的基本語法和語義
這次,我來概述標準c++異常處理的基本語法和語義。順便,我會將它和前兩次提到的技術進行比較。(在本文及以後,我將標準c++異常處理簡稱為eh,將微軟的方法稱為seh。)
1.1 基本語法和語義
eh引入了3個新的c++語言關鍵字:
l catch
l throw
l try
異常通過如下語句觸發
throw [expression]
函式通過「異常規格申明」定義它將丟擲什麼異常:
throw([type-id-list])
可選項type-id-list包含乙個或多個型別的名字,以逗號分隔。這些異常靠try塊中的異常處理函式進行捕獲。
try compound-statement handler-sequence
處理函式佇列包含乙個或多個處理函式,形式如下:
catch ( exception-declaration ) compound-statement
處理函式的「異常申明」指明了這個函式將捕獲什麼型別的異常。
和seh一樣,跟在try和catch後面的語句必須刮在{}內,而整個try塊組成一條完整的大語句。
例子:void f() throw(int, some_class_type)
int main()
catch(int e)
catch(some_class_type e)
// ... possibly other handlers ...
return 0; }
異常規格申明是eh特有的,seh和mfc都沒有類似的東西。乙個空的異常規格申明表明函式不丟擲任何異常:
void f() throw()
如果函式沒有異常規格申明,它可以丟擲任何型別的異常:
void f()
當函式拋異常時,關鍵字throw通常後面帶乙個被丟擲的物件:
throw i;
然而,throw也可以不帶物件:
catch(int e)
它的效果是再次丟擲當前正**獲的物件(int e)。因為空throw的作用是再次丟擲已存在的異常物件,所以它必須位於catch語句塊中。mfc也有再次丟擲異常的功能,seh則沒有,它沒有將異常物件交給過處理函式,所以沒什麼可再次丟擲的。
就象函式原型中的引數申明一樣,異常申明也可以是無名的:
catch(char *)
當這個處理函式捕獲乙個char *型的異常物件時,它不能操作這個物件,因為這個物件沒有名字。
異常申明還可以是這樣的特殊形式:
catch(...)
就象不定引數中的「...」一樣,異常申明中的「...」可以匹配任何異常的型別。
1.2 標準異常物件的型別
標準庫函式可能報告錯誤。在c標準庫中的報錯方式在前面說過了。在c++標準庫中,有些函式丟擲特定的異常,而另外一些根本不拋任何異常。
因為c++標準中沒有明確規定,所以c++的庫函式可以丟擲任何物件或不拋。但c++標準推薦執行庫的實現通過丟擲定義在中的異常型別或其派生型別來報告錯誤:
namespace std
這些(異常)類只對c++標準庫有約束力。在你自己的**中,你可以丟擲(和捕獲)任何你所象要的型別。
1.3 標準中的其它申明
標準庫標頭檔案申明了幾個eh型別和函式
namespace std
提要:l exception是所有標準庫丟擲的異常的基類。
l uncaught_exception()函式在有異常被丟擲卻沒有**獲時返回true,其它情況返回false。它類似於seh的函式abnormaltermination()。
l terminate()是eh的應急處理。它在異常處理體系陷入了不可恢復狀態時被呼叫,經常是因為試圖重入(在前乙個異常正處理過程中又拋了乙個異常)。
l unexpected()在函式丟擲乙個它沒有在「異常規格申明」中申明的異常時被呼叫。這個預料外的異常可能在退棧過程中被替換為乙個bad_excetion物件。
l 執行庫提供了預設terminate_handler()和unexpected_handler() 函式處理對應的情況。你可以通過set_terminate()和set_unexpected()函式替換庫的預設版本。
1.4 異常生命期
eh執行於異常生命期的五個階段:
l 程式或執行庫遇到乙個錯誤狀況(階段1)並且丟擲乙個異常(階段2)。
l 程式的執行停止於異常點,開始搜尋異常處理函式。搜尋沿呼叫棧向上搜尋(很象seh終止異常時的行為)。
l 搜尋結束於找到了乙個異常申明與異常物件的靜態型別相匹配(階段3)。於是進入相應的異常處理函式。
l 異常處理函式結束後,跳到此異常處理函式所在的try塊下面最近的一條語句開始執行(階段5)。這個行為意味著c++標準中異常總是終止。
這些步驟演示於這個簡單的例子中:
#include
static void f(int n)
extern int main()
catch(int) // stage 3
catch(char *) // stage 3
catch(...) // stage 3
// stage 5
printf("terminating, after ´try´ block/n");
return 0; }
/*when run yields
caught ´int´ exception
terminating, after ´try´ block */
1.5 基本原理
c標準庫的異常體系處理c++語言時有如下難題:
l 析構函式被忽略。既然c標準庫異常體系是為c語言設計的,它們不知道c++的析構函式。尤其,abort()、exit()和longjmp()在退棧或程式終止時不呼叫區域性物件的析構函式。
l 繁瑣的。查詢全域性物件或函式返回值導致了**混亂-你必須在所有可能發生異常的地方進行明確的異常情況檢測,即使是異常情況可能實際上從不發生。因為這種方法是如此繁瑣,程式設計師們可能會故意「忘了」檢測異常情況。
l 無彈性的。longjmp()「丟擲」的只能是簡單的int型。errno和signal()/raise()只使用了很小的乙個值域集合,解析度很低。abort()和exit()總是終止程式。assert()只工作在debug版本中。
l 非固有的。所有的c標準庫異常體系都需要執行庫的支援,它不是語言核心支援的。
微軟特有的異常處理體系也不是沒有限制的:
l seh異常處理函式不是直接捕獲乙個異常物件,而是通過查詢乙個(概念性的)類似errno的全域性值來判斷什麼異常發生了。
l seh異常處理函式不能組合,給定try塊的唯有的乙個處理函式必須在執行期識別和處理所有的異常事件。
l mfc異常處理函式只能捕獲cexception及派生型別的指標。
l 通過包含定義了mfc異常處理函式的巨集的標頭檔案,程式包含了數百個無關的巨集和申明。
l mfc和seh都是專屬於與microsoft相容的開發環境和windows執行平台的。
標準c++異常處理避免了這些短處:
l 析構安全。在拋異常而進行退棧時,區域性物件的析構函式被按正確的順序呼叫。
l 不引人注目的。異常的捕獲是暗地裡的和自動的。程式設計師無需因錯誤檢測而搞亂設計。
l 精確的。因為幾乎任何物件都可以被丟擲和捕獲,程式設計師可以控制異常的內容和含義。
l 可伸縮的。每個函式可以有多個try塊。每個try塊可以有單個或一組處理函式。每個處理函式可以捕獲單個型別,一組型別或所有型別的異常。
l 可**的。函式可以指定它們將拋的異常型別,異常處理函式可以指定它們捕獲什麼型別的異常。如果程式違反了其申明,標準庫將按可**的、使用者定義的方式執行。
l 固有的。eh是c++語言的一部分。你可以定義、throw和catch異常而不需要包含任何庫。
l 標準的。eh在所有的標準c++的實現中都可用。
基於更完備的想法,c++標準委員會考慮過兩個eh的設計,在d&e的16章。(for a more complete rationale, including alternative eh designs considered by the c++ standard´s committee, check out chapter 16 of the d&e.)
1.6 小結
下次,我將更深入挖掘eh的語言核心特性和eh的標準庫支援。我也將展示microsoft visual c++實現eh的內幕。我將開始標誌出eh的那些visual c++只部分支援或完全不支援的特性,並且尋找繞過這些限制的方法。
在我相信設計eh的基本原理是健全的的同時,我也認為eh無意中包含了一些嚴重的後果。不用責備c++標準的制訂者的短視,我理解設計和實現有效的異常處理是多麼的難。當我們遭遇到這些無意中的後果時,我將展示它們對你**的微妙影響,並且推薦一些技巧來減輕其影響。
C 講座 3 C 中異常的處理
異常概述exception 捕獲異常及處理 跟蹤trace 異常是當程式發生錯誤時產生的一種訊號 異常的型別 處理方式 1異常被物件所表現而並不是錯誤 2異常的產生是通過throwing乙個該異常的物件實現的 3異常的捕獲是通過catch該異常的物件 4命名上可以讀出是哪類異常 捕獲異常try ca...
C 中的異常處理
在program.cs中新增如下 之後整個應用程式都不需要額外處理異常了。所以的異常都會在這裡處理 補充 還需要考慮沒有檔案的寫許可權,catch unauthorizedacces ception ex access to the path d chucklu git edenred lisa 5...
c 中的異常處理
異常的概念 程式在執行過程中可能產生異常 異常 exception 與bug的區別 異常是程式執行時可預料的執行分支 bug是程式中的錯誤,是不被預期的執行方式 異常 exception 和bug的對比 異常執行時產生除0的情況 需要開啟的外部檔案不存在 陣列訪問時越界 bug使用野指標 堆陣列使用...