2013-04-26 76 views
1

在我編寫的應用程序中,我對大多數錯誤處理使用異常。我沒有定義自己的異常類,只是還沒有,我只是做了以下內容:拋出異常時應用程序崩潰

namespace Mage { 
    typedef std::exception Exception; 
} 

這樣,我不會改變我的所有代碼時,我以後定義自己的類型,應使用相同的接口。

也就是說,任何異常都會崩潰我的應用程序。考慮到上述定義,爲什麼會這樣崩潰?

void Mage::Root::initialize(Mage::String& p_log) { 
    // initialize GLFW and GLEW. 
    if (!glfwInit()) { 
     throw new Mage::Exception("failed to initialize OpenGL"); 
     return; 
    } else m_GLFWInitialized = true; 

無論我是否刪除或保留「新」,它仍會崩潰。我錯過了什麼嗎?我已經看過教程,但這些並沒有讓我明白。

我也搭上了錯誤就在這裏:

try { 
    MAGE_ROOT.initialize(Mage::String("Mage.log")); 
} catch (Mage::Exception& e) { 
    std::cerr << e.what() << std::endl; 
} 

我得到的崩潰是:

Debug Error! 

Program: ...sual Studio 2010\Project\Mage3D\Binaries\Debug\Test.exe 

R6010 
- abort() has been called 

(Press Retry to debug application) 
+6

你如何看待你的例外? – 2013-04-26 12:43:35

+0

我想,那個地方,*你拋出異常的地方也是相關的。通常在析構函數中拋出異常可能導致這樣的錯誤。 – Spook 2013-04-26 12:44:36

+0

你很喜歡捕捉異常,對吧? – 2013-04-26 12:44:50

回答

11

問題是,你沒有捕捉到你的例外。

我不知道你-have-(從評論

是的,你必須趕上例外。如果你沒有發現拋出的異常,將會調用std::terminate()。這是預期的行爲:存在例外,以防止程序員忘記關於錯誤處理的

這就是說,我建議:由價值

  • 投擲;
  • 醒目參照

例如:

void foo() 
{ 
    // ... 
    throw std::logic_error("Error!"); 
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    // Throw by value (std::logic_error derives from std::exception) 
    // ... 
} 

void bar() 
{ 
    try 
    { 
     // ... 
     foo(); 
     // ... 
    } 
    catch (std::exception& e) 
      ^^^^^^^^^^^^^^^ 
    //  Catch by reference 
    { 
     std::cout << e.what(); // For instance... 
    } 
} 

UPDATE:

至於這塊您發佈的代碼,你扔一個指針和捕參考。處理程序不匹配。並且由於沒有其他匹配處理程序,因此將調用std::terminate()

相反,你應該通過值拋出你的異常:

throw Mage::Exception("failed to initialize OpenGL"); 

如果你發佈的代碼確實是您正在使用的一個,你會看到,控制轉移到您的處理程序。

+0

謝謝。那樣做了。 – 2013-04-26 13:03:00

+0

@JesseBrands:很高興幫助。 – 2013-04-26 13:04:37

2

基於該錯誤消息,您正在使用的Visual Studio(2010)爲你的項目。除非你把你的throw放在try/catch塊中,否則它將「通過屋頂航行」並被C++運行時「處理」,這意味着調用abort()。你可能想是在調用堆棧這個更高:

​​

還要注意斯科特邁爾斯建議總是通過引用捕獲異常。 「異常」:如果您使用的是MFC CExceptions,但您希望通過指針捕獲並調用Delete方法來自毀基於堆的異常。

根據您的編輯,您可能在投擲「通過指針」和捕捉「通過引用」之間不匹配。如果你已經解決了這個問題並且仍然沒有讓你的catch塊執行,你可以嘗試使用CRT SetAbortHandler來調試abort()調用來安裝你自己的中止函數。這可以簡單地鏈接到現有的一個,但會提供一個機會來設置斷點並檢查調用堆棧以查看發生了什麼問題。

0

C++ try-catch-throw邏輯假人。請注意,這不包括RAII /基於堆棧的分配/銷燬。

  • 當你拋出一個異常,異常被認爲是「傳播」。它傳播調用堆棧,直到找到可以處理它的第一個處理程序(因此被捕獲)或直到它到達調用堆棧的根目錄爲止。
    • 如果被捕獲,執行從異常被捕獲的時刻開始繼續。異常在catch塊的末尾被破壞。
    • 如果找到根,它會調用std :: unhandled_exception,通常會調用std :: terminate,通常會調用abort()。總之,一切都儘快下降。
  • 如果您在異常當前正在傳播時拋出異常,那麼您將有兩次傳播。 Java和C#擁有可愛的處理方式,但這絕不應該發生在第一位 - 沒有任何異常處理程序在邏輯上處理異常組合。當前正在傳播的時候不要拋出異常。即使你不使用std :: uncaught_exception(),你也不應該這樣做。
  • 展開堆棧/傳播異常時,堆棧中找到的所有對象都被破壞。這些析構函數不應該拋出異常 - 畢竟,當銷燬一個對象「失敗」時,在析構函數修復之後你還會做什麼?
  • 永遠拋棄價值,引用參考。如果你通過指針捕獲&,你很可能會泄漏一些東西,這是不可能的。如果您按值捕獲,您將切斷您的派生異常類型。抓住參考。
  • 在您的軟件的根源中,包含全部 - catch(...)。這不能讓你發現你到底抓到了什麼,但至少你可以安全地墜毀。當被調用的代碼可能拋出你不知道的「某些東西」時,也要這樣做。
相關問題