C與C++中的異常處理2(part2) (轉)
1.1 版本3:恢復異常:namespace prefix = o ns = "urn:schemas--com::office" />
接下來,改:
__except(except_filter(3, EXCEPTION_CONTINUE_SEARCH))
為:
__except(except_filter(3, EXCEPTION_CONTINUE_EXECUTION))
重新編譯並執行。可以看到這樣的輸出:
0:before first try
1: try
2: try
3: try
4: try
4: raising exception
3: filter => EXCEPTION_CONTINUE_EXECUTION
4: after exception
4: handling normal tenation
3: continuation
2: continuation
2: handling normal termination
1: continuation
0:continuation
因為第三層的異常過濾器已經捕獲了異常,第一層的過濾器不會被求值。捕獲異常的過濾器求值為EXCEPTION_CONTINUE_EXECUTION,因此異常被恢復。異常處理不會被進入,將從異常發生點正常下去。
1.2 版本4:異常終止
這樣的結構:
__try
{
/* ... */
return;
}
或:
__try
{
/* ... */
goto label;
}
__finally
{
/* ... */
}
/* ... */
label:
被認為是try塊異常終止。以後AbnormalTermination()函式的話將返回非0值,就象異常仍然存在。
要看其效果,改這兩行:
trace(4, "raising exception");
RaiseException(exception_code, 0, 0, 0);
為:
trace(4, "exiting try block");
goto end_4;
第4層的try塊不是被一個異常結束的,現在是被goto語句結束的。執行結果:
0:before first try
1: try
2: try
3: try
4: try
4: exiting try block
4: handling abnormal termination
3: continuation
2: continuation
2: handling normal termination
1: continuation
0:continuation
第4層的終止處理函式認為它正在處理異常終止,雖然並沒有發生過異常。(如果發生過異常的話,我們至少能從一個異常過濾器的輸出資訊上看出來的。)
結論:你不能只依賴AbnormalTermination()函式來判斷異常是否仍存在。
1.3 版本5:正常終止
如果想正常終止一個try塊,也就是想要AbnormalTermination() 函式返回FALSE,應該使用Microsoft特有的關鍵字__leave。想驗證的話,改:
goto end_4;
為:
__leave;
重新編譯並執行,結果是:
0:before first try
1: try
2: try
3: try
4: try
4: exiting try block
4: handling normal termination
3: continuation
2: continuation
2: handling normal termination
1: continuation
0:continuation
和版本4的輸出非常接近,除了一點:第4層的終止處理函式現在認為它是在處理正常結束。
1.4 版本6:隱式異常
前面的版本處理的都是產生的異常。SEH也可以處理自己丟擲的異常。
改這行:
trace(4, "exiting try block");
__leave;
為:
trace(4, "implicitly raising exception");
*((char *) 0) = 'x';
這導致Windows的操作異常(引用空指標)。接著改:
__except(except_filter(3, EXCEPTION_CONTINUE_EXECUTION))
為:
__except(except_filter(3, EXCEPTION_EXECUTE_HANDLER))
以使程式捕獲並處理異常。
執行結果為:
0:before first try
1: try
2: try
3: try
4: try
4: implicitly raising exception
3: filter => EXCEPTION_EXECUTE_HANDLER
4: handling abnormal termination
3: handling exception
2: continuation
2: handling normal termination
1: continuation
0:continuation
如我們所預料,Windows在巢狀層次4中觸發了一個異常,並被層次3的異常處理函式捕獲。
如果你想知道捕獲的精確異常碼,可以讓異常傳到main外面去,就象版本2中做的。為此,改:
__except(except_filter(3, EXCEPTION_EXECUTE_HANDLER))
為:
__except(except_filter(3, EXCEPTION_CONTINUE_SEARCH))
結果對話方塊在按了“Details”後,顯示的資訊非常象使用者異常。
圖3 記憶體異常對話方塊
和版本2的對話方塊不同是,上次顯示了特別的異常碼,這次說了“invalid page fault”--更使用者友好些吧。
1.5 C++考慮事項
在所有C相容異常處理體系中,SEH無疑是最完善和最靈活的(至少在Windows環境下)。具有諷刺意味的,它也是Windows體系以外的環境中最不靈活的,它將你和特殊的執行平臺及Visaul C++原始碼相容的牢牢綁在了一起。
如果只使用C語言,並且不考慮移植到Windows平臺以外,SEH很好。但如果使用C++並考慮可移植性,我強烈建議你使用標準C++異常處理而不用SEH。你可以在同一個程式中同時使用SEH和標準C++異常處理,只有一個限制:如果在有SEH try塊的函式中定義了一個,而這個物件又沒有non-trivial(無行為的)解構函式,編譯器會報錯。在同一函式中同時使用這樣的物件和SEH的__try,你必須禁掉標準C++異常處理。
(Visual C++預設關掉標準C++異常處理。你可以使用命令列引數/GX或的Project Settings對話方塊開啟它。)
在以後的文章中,我會在討論標準C++異常處理時回顧SEH。我想將SEH整合入C++的主流中,透過將結構化異常及Windows執行庫支援對映為C++異常和標準C++執行庫支援。
1.6 MFC異常處理
說明:這一節我需要預先引用一點點標準C++異常處理的知識,但要到下次才正式介紹它們。這個提前引用是不可避免的,也是沒什麼可驚訝的,因為Microsoft將它們的MFC異常的語法和語義構建在標準C++異常的語法和語義的基礎上。
我到現在為止所講的異常處理方法對C和C++都有效。在此之外,Microsoft對C++程式還有一個解決方案:MFC異常處理類和宏。Microsoft現在認為MFC異常處理體系過時了,並鼓勵你儘可能使用標準C++異常處理。然而Visual C++仍然支援MFC異常類和及宏,所以我將給它個簡單介紹。
Microsoft用標準C++異常實現了MFC3.0及以後版本。所以你必須啟用標準C++異常才能使用MFC,即使你不打算顯式地使用這些異常。前面說過,你必須禁掉標準C++異常來使用SEH,這也意味著你不能同時使用MFC宏和SEH。Microsoft明文規定這兩個異常體系是互斥的,不能在同一程式中混合使用。
SEH是擴充套件了編譯器關鍵字集,MFC則定義了一組宏:
l TRY
l CATCH, AND_CATCH, 和END_CATCH
l THROW 和 THROW_LAST
這些宏非常象C++的異常關鍵字try、catch和throw。
另外,MFC提供了異常類體系。所有名字為CXXXException形式的類都是從抽象類CException派生的。這類似於標準C++執行庫在
對於每個MFC異常類CXXXException,都有一個全域性的輔助函式AfxThrowXXXException() ,它構造、初始化和丟擲這個類的物件。你可以用這些輔助函式處理預定義的異常型別,用THROW處理自定義的物件(當然,它們必須是從CException派生的)。
基本的設計原則是:
l 用TRY塊包含可能產生異常的程式碼。
l 用CATCH檢測並處理異常。異常處理函式並不是真的捕獲物件,它們其實是捕獲了指向異常的指標。MFC靠動態型別來辨別異常物件。比較一下,SEH靠執行時查詢異常碼來辨別異常。
l 可以在一個TRY塊上捆綁多個異常處理函式,每個捕獲一個C++靜態型別不同的物件。第一個處理函式使用宏CATCH,以後的使用AND_CATCH,用END_CATCH結束處理函式佇列。
l MFC自己可能觸發異常,你也可以顯式觸發異常(透過THROW或MFC輔助函式)。在異常處理函式內部,可以用THROW_LAST再次丟擲最近一次捕獲的異常。
l 異常一被觸發,異常處理函式就將被從裡到外進行搜尋,和SEH時一樣。搜尋停止於找到一個型別匹配的異常處理函式。所有異常都是終止。和SEH不一樣,MFC沒有終止處理函式,你必須依賴於區域性物件的解構函式。
一個小MFC例子,將大部分題目都包括了:
#include
#include "afxwin.h"
void f()
{
TRY
{
printf("raising memory exceptionn");
AfxThrowMemoryException();
printf("this line should never appearn");
}
CATCH(CException, e)
{
printf("caught generic exception; rethrowingn");
THROW_LAST();
printf("this line should never appearn");
}
END_CATCH
printf("this line should never appearn");
}
int main()
{
TRY
{
f();
printf("this line should never appearn");
}
CATCH(CFileException, e)
{
printf("caught file exceptionn");
}
AND_CATCH(CMemoryException, e)
{
printf("caught memory exceptionn");
}
/* ... handlers for other CException-derived types ... */
AND_CATCH(CException, e)
{
printf("caught generic exceptionn");
}
END_CATCH
return 0;
}
/*
When run yields
raising memory exception
caught generic exception; rethrowing
caught memory exception
*/
記住,異常處理函式捕獲指向物件的指標,而不是實際的物件。所以,處理函式:
CATCH(CException, e)
{
// ...
}
定義了一個區域性指標CException *e指向了被丟擲的異常物件。基於C++的多型,這個指標可以引用任何從CException派生的物件。
如果同一try塊有多個處理函式,它們按從上到下的順序進行匹配搜尋的。所以,你應該將處理最派生類的物件的處理函式放在前面,不然的話,更派生類的處理函式不會接收任何異常的(再次拜多型所賜)。
因為你典型地想捕獲CException,MFC定義了幾個CException特有宏:
l CATCH_ALL(e)和AND_CATCH_ALL(e),等價於CATCH(CException, e)和AND_CATCH(CException, e)。
l END_CATCH_ALL ,結束CATCH_ALL... AND_CATCH_ALL佇列。
l END_TRY等價於CATCH_ALL(e);END_CATCH_ALL。這讓TRY... END_TRY中沒有處理函式或說是接收所有丟擲的異常。
這個被指的異常物件由MFC隱式析構和歸還記憶體。這一點和標準C++異常處理函式不一樣,MFC異常處理不會讓任何人取得被捕獲的指標的所有權。因此,你不能用MFC和標準C++體系同時處理相同的異常物件;不然的話,將導致記憶體洩漏:引用已被析構的物件,並重復析構和歸還同一物件。
1.7 小結
MSDN線上還有另外幾篇探索結構化異常處理和MFC異常宏的文章。
下次我將介紹標準C++異常,概述它們的特點及基本原理。我還會將它們和到現在已經看到的方法進行比較。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992206/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- C與C++中的異常處理 (轉)C++
- C與C++中的異常處理11 (轉)C++
- C與C++中的異常處理13 (轉)C++
- C與C++中的異常處理12 (轉)C++
- C與C++中的異常處理14 (轉)C++
- C與C++中的異常處理15 (轉)C++
- C與C++中的異常處理16 (轉)C++
- C與C++中的異常處理17 (轉)C++
- C與C++中的異常處理3 (轉)C++
- C與C++中的異常處理4 (轉)C++
- C與C++中的異常處理5 (轉)C++
- C與C++中的異常處理7 (轉)C++
- C與C++中的異常處理6 (轉)C++
- C與C++中的異常處理9 (轉)C++
- C與C++中的異常處理8 (轉)C++
- C與C++中的異常處理10 (轉)C++
- C與C++中的異常處理2(part1) (轉)C++
- c++ 異常處理(2)C++
- c++異常處理 (轉)C++
- C++ 異常處理C++
- C++異常處理C++
- C++異常處理與臨時副本C++
- c++異常處理格式C++
- c++ 異常處理(1)C++
- windows核心程式設計---未處理異常,向量化異常處理與C++異常Windows程式設計C++
- 【C++】 C++異常捕捉和處理C++
- C++異常處理機制C++
- C++編譯器怎麼實現異常處理2 (轉)C++編譯
- 深入理解C++中的異常處理機制C++
- C++錯誤和異常處理C++
- C++整理19_異常處理C++
- 【C++】 63_C語言異常處理C++C語言
- C++ 異常處理機制詳解:輕鬆掌握異常處理技巧C++
- C++ 異常處理機制的實現C++
- 強制型別轉換時的異常處理_java與c++比較型別JavaC++
- Linux 下 C++ 異常處理技巧LinuxC++
- C++和結構化異常處理C++
- C/C++學習筆記八(斷言與異常處理)C++筆記