2013-07-01 104 views
15
A:  catch(...) 
B:  catch(std::exception& e) 

問題是A可以捕獲但B不能。std :: exception和「...」之間的區別

爲什麼在C++中通用的根異常,可以捕捉到任何沒有出臺

---附加 我很抱歉,我應該說我用C明白++,你可以拋出任何類型如int,但除此之外,還有什麼可以拋出的?

我的問題是,我試圖找到什麼異常是從代碼引發的,它可以被A但不是B捕獲。這個異常絕對不是像「int」這樣的類型。它必須是系統異常或內存違規類的事情。我只是想知道那可能是什麼。

+0

C++沒有 '根' 的異常類型所有異常繼承,因爲C++可以拋出任何東西,包括不能繼承的類型;例如'int'。 C++可以拋出任何東西,因爲他們沒有看到讓異常變得不那麼普遍的理由。它類似於C++模板; C++模板不依賴於繼承,因此比一般依賴繼承的Java或C#泛型更通用。 – bames53

+1

某些Windows SEH異常有時可能被'...'發現,但不會被'std :: exception'發現。只有當你瘋狂的標誌編譯,使用推薦/ EHSC(如果可以的話),你會被罰款 –

+0

@MooingDuck –

回答

28

catch (...)是一個所謂的「catch all」塊。它會捕獲任何 C++異常。

catch(std::exception& e)將捕獲只有std::exception派生的例外。

這裏是一個將被捕獲所有被稱爲一個例外的例子,但不是第二個版本:

throw 42; 

這聽起來很奇怪,你,它是。要認識到的重要一點是,任何東西都可以作爲C++異常拋出 - 不僅僅是exception或從exception派生的東西。正如@ bames53在註釋中提到的那樣,沒有任何異常類型來源於所有異常,就像其他語言一樣。

重要的是要注意,一個全通塊很容易被濫用。事實上,作爲一般的經驗法則,最好假設所有全部封鎖都是程序缺陷。當然,編程中並沒有「永遠」,但是當你學習使用異常時,這是一個安全的假設。

爲什麼catch-all模塊是邪惡的原因是因爲它們通常如何使用。通常情況下,一個天真的程序員會編寫一個捕獲所有程序來試圖捕捉任何編程錯誤,然後批判地繼續讓程序運行,就好像什麼也沒發生一樣。這是一場等待發生的災難。程序狀態現在是不確定的。某個地方出了問題。你不能安全地忽略異常,並繼續像一切都很好。即使你的程序繼續運行,可能會在某處發生微妙的堆損壞,會摻雜程序的計算或其輸出。發生堆損壞時,作爲程序員可以希望的最好的事情是立即崩潰。這樣你就可以在腐敗點得到一個調用堆棧和一個轉儲文件,並找到並解決問題。但是,當你有一個全面的地方,你已經失去了腐敗發生的所有背景。在你的代碼中找到真正的缺陷幾乎是不可能的。


當然,捕獲所有處理程序是有效的和有價值的用法。最常見的一種情況是編寫一個全局異常處理程序,然後重新編號爲throw。這個全局處理程序可以啓動某種故障記錄,可能是通過記錄錯誤本身,或者產生一個外部程序來記錄失敗程序以外的記錄。通過重新拋出異常,您可以爲委託人提供處理可以處理的異常的機會,同時允許無法處理的異常終止程序。

重新執行異常很簡單。只需撥打throw不帶參數,如:

catch (...) 
{ 
    // some magic 
    throw; 
} 

另一件事要記住的是,當你做捕獲一個例外,它通常最好趕const參考,而不是隻是一個參考。

+5

此外,一些老版本VC++的(甚至有某些設置更新)也陷入異常SEH用' catch(...)',這絕對不是一個好主意(你可能最終會忽略訪問衝突或用於擴展堆棧的頁面防護例外)。 –

+0

@MatteoItalia:你確定嗎?我已經和SEH打交道已經很長時間了,你可能是對的,但我不記得。 –

+0

我不確定舊的默認行爲,但您仍然可以更改設置以啓用捕獲SEH異常。 – jerry

1

int s怎麼樣?

try { 
    throw 123; 
} catch (std::exception &e) { 
    // this won't catch 
} catch (...) { 
    // this will catch 
} 
2

簡短的答案是什麼,沒有它的(公共)繼承層次結構std::exception

#include <exception> 
#include <iostream> 

int main() 
{ 
    try 
    { 
     throw false; 
    } 
    catch(std::exception& e) 
    { 
     std::cout << "Caught std::exception" << std::endl; 
    } 
    catch(...) 
    { 
     std::cout << "Caught something else" << std::endl; 
    } 

    return 0; 
} 

輸出:

Caught something else
相關問題