2008-12-15 48 views
9

我發現了一些代碼的項目,它看起來像這樣:在主要(...)中捕獲異常是否有意義?

int main(int argc, char *argv[]) 
{ 
    // some stuff 

try { 
    theApp.Run(); 
} catch (std::exception& exc) { 
    cerr << exc.what() << std::endl; 
    exit(EXIT_FAILURE); 
} 
return (EXIT_SUCCESS); 
} 

我不明白爲什麼例外被捕獲。如果不是,應用程序將退出並打印異常。

您是否看到有什麼理由在這裏發現異常?


編輯:我同意這是很好的打印異常錯誤。但是,重新拋出異常不是更好嗎?我有這樣的感覺,我們正在這裏吞嚥它...

+0

如何吞嚥?代碼打印異常消息,然後退出。你還能做什麼?如果你重新拋出異常,誰會看到它?它會被抓到哪裏?畢竟,這是該計劃的切入點。 – jalf 2008-12-15 17:00:59

回答

15

如果未捕獲到異常,則標準沒有定義堆棧是否展開。所以在某些平臺上會調用析構函數,而在其他平臺上,程序將立即終止。捕捉頂層確保始終調用析構函數。因此,如果你沒有在調試器下運行,那麼抓住所有東西(......)以及std :: exception也許是明智的。然後,即使在致命的異常情況下,您的應用程序代碼也可以用RAII清理。在許多這樣的情況下,你並不需要清理,因爲操作系統會爲你做。但是,舉例來說,如果可能的話,您可能更願意從遠程服務中徹底斷開連接,並且可能會有流程外部的資源,例如命名管道/互斥鎖,而您更願意銷燬而不是泄漏。

由於您已經丟失了最初拋出的上下文,因此重新調整主程序中的異常似乎對我的使用有限。我想假設在調試器中捕獲未捕獲的異常比僅將錯誤記錄到std :: cerr更加噪聲,所以如果有可能丟失日誌記錄,重新拋出將是明智之舉。

如果您希望調試器在調試模式下捕獲意外情況(在發佈模式下會拋出一個最終導致退出的異常),那麼還有其他方法可以做到這一點,而不是讓未調用的異常讓調試器看到它。例如,你可以使用assert宏。當然,這對於意外和不可預知的情況無濟於事,例如,如果您在.NET上使用SEH,則會出現硬件異常。

6

你爲什麼說這個例外會被打印?這不是C++運行時的典型行爲。充其量,你可以期望它的類型得到打印。此外,該程序處於「失敗」狀態,而異常可能導致終止中止狀態(即退出代碼中指示的信號)。

+0

你是對的,我錯誤地認爲會打印異常。事實並非如此。 – Barth 2008-12-15 12:24:14

3

這是一個全局catch塊。顯示一個好的和用戶理解的消息('內部錯誤')而不是一個神祕的異常打印是很常見的。這從特定的代碼塊可能不明顯,但它通常是一個好主意。

+0

這只是一個好主意,直​​到你第一次調試一些神祕的異常,從地獄中拋出知道在哪裏...... :) – Paulius 2008-12-15 12:34:25

+1

然後我們不能打印它並重新拋出它嗎? – Barth 2008-12-15 12:42:19

+0

我想我們可以,但是當我正在調試時 - 我很少看看打印的內容 - 我通常會在觀察窗口中查看數值(如果需要的話)。 – Paulius 2008-12-15 13:14:53

6

主函數中的Try-catch隱藏調試器的異常。我會說,這不好。

另一方面,客戶不希望有調試器,因此捕捉異常很好。所以這很好。

就個人而言,我在製作發佈版本時捕獲主函數中的所有異常,而在構建調試配置時我不這麼做。

0

看看C++聖經,即Stroustrup,他有一個例子,它在Applied C++編程中也有重複。原因是:

int main(void) 
{ 
    try 
    { 
      // your code 
    } 
    catch (/* YourPossibleExceptions i.e. barfs you expect may occur */) 
    { 
    } 
    catch (...) // unexpected errors, so you can exit gracefully 
    { 
    } 
} 
4

的情況下一個簡單的例子,其堆疊並沒有放鬆:
Why destructor is not called on exception?

的情況列表,其中的異常可能會導致應用程序終止,而不是展開堆棧。
Why destructor is not called on exception?

如果一個異常沒有在任何級別抓,並會逃跑的main(),則實現被允許調用終止(),而該棧展開(是的,這抓住了我措手不及爲好)。

因此,我總是捕獲main()中的所有異常。

int main() 
{ 
    try 
    { 
    } 
    catch(std::exception const& e) 
    { /* LOG */ 
     // optimally rethrow 
    } 
    catch(...) // Catch anything else. 
    { /* LOG */ 
     // optimally rethrow 
    } 
} 

在調試過程中幫助捕捉問題。從std :: exception派生你的異常,然後在std :: exception的構造函數中插入斷點。

0

根據Windows規範,main不允許扔。 (實際上,它會導致消息詢問您是否要將錯誤報告發送給Microsoft)