簡體   English   中英

引發異常時應用程序崩潰

[英]Application crashes when throwing an exception

在我正在編寫的應用程序中,大多數錯誤處理都使用異常。 我還沒有定義自己的異常類,我只做了以下工作:

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)

問題是您沒有捕捉到異常。

我不知道您-必須-捕獲異常( 來自評論

是的,你必須。 如果未捕獲到引發的異常,則將調用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...
    }
}

更新:

關於您發布的代碼,您將拋出一個指針並被引用捕獲。 處理程序將不匹配。 並且由於沒有其他匹配的處理程序,因此將調用std::terminate()

相反,您應該按值拋出異常:

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

如果您發布的代碼確實是您正在使用的代碼,您將看到控件已轉移到您的處理程序。

根據錯誤消息,您將Visual Studio(2010)用於項目。 除非您將throw包裹在try / catch塊中,否則它將“穿過屋頂”並由C ++運行時“處理”,這意味着調用abort()。 您可能希望在調用堆棧中添加類似以下內容:

try
{
   SomeFunctionThatUltimatelyThrows();
}
catch(Exception & e)
{
   // .. handle error - log, resume, exit, whatever
}

另請注意,Scott Meyers建議始終通過引用來捕獲異常。 “例外”:如果使用的是MFC CException,則希望通過指針捕獲並調用Delete方法以自毀基於堆的異常。

根據您的編輯,在“按指針”拋出和“按引用”捕獲之間可能不匹配。 如果您已解決該問題,但仍無法執行catch塊,則可以嘗試使用CRT SetAbortHandler來安裝您自己的中止函數,以調試abort()調用。 這可以簡單地鏈接到現有的鏈接中,但是可以提供一個設置斷點和檢查調用堆棧的機會,以查看發生了什么問題。

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

  • 當引發異常時,異常被稱為“傳播中”。 它在調用堆棧中傳播,直到找到第一個可以處理它的處理程序(這樣它就被捕獲了),或者到達了您的調用堆棧的根為止。
    • 如果捕獲到該異常,則從捕獲到異常的那一點開始繼續執行。 異常在catch塊的末尾被破壞。
    • 如果找到根,它將調用std :: unhandled_exception,通常調用std :: terminate,通常調用abort()。 簡而言之,一切都已迅速消失。
  • 如果在當前正在傳播異常的同時拋出異常,則一次將傳播兩個。 Java和C#具有處理這種情況的可愛方法,但是這種情況一開始就不應該發生-從邏輯上講,沒有異常處理程序將處理異常的組合。 當前正在傳播時,請勿拋出異常。 即使您不使用不應該使用的std :: uncaught_exception(),該規則也不難掌握。
  • 在展開堆棧/傳播異常時,堆棧上找到的所有對象均被破壞。 這些析構函數永遠都不會拋出異常-畢竟,當銷毀一個對象“失敗”時,在析構函數對其進行修復之后您還需要做什么?
  • 總是按價值投擲,按參考抓住。 如果您通過指針拋出並捕捉,很可能會泄漏某些東西,而這是通過引用無法實現的。 如果按值捕獲,則將分割派生的異常類型。 通過引用捕獲。
  • 在您的軟件的根本,包括一個包羅萬象的catch(...) 這不能讓您找出確切捕獲的內容,但是至少您可以安全地崩潰。 當被調用的代碼可能拋出您不知道的“東西”時,也要執行此操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM