抛出异常时应用程序崩溃

时间:2013-04-26 12:42:38

标签: c++ 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;

无论我删除还是保留'new',它都会崩溃。我错过了什么吗?我已经查阅了教程,但那些并没有让我更聪明。

我也在这里发现错误:

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)

3 个答案:

答案 0 :(得分:11)

问题是你没有发现你的异常。

  

我不知道你 - 有 - 抓住异常(来自评论

是的,你必须这样做。如果您没有捕获抛出异常,将调用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");

如果您发布的代码确实是您正在使用的代码,您将看到该控件已转移到您的处理程序。

答案 1 :(得分:2)

根据错误消息,您正在为项目使用Visual Studio(2010)。除非你将throw包装在try / catch块中,否则它将“通过屋顶”并由C ++运行时“处理”,这意味着调用abort()。您可能希望调用堆栈中的内容更高:

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

另请注意,Scott Meyers建议始终通过引用捕获异常。 “异常”:如果您正在使用MFC CExceptions,您希望通过指针捕获并调用Delete方法来自毁基于堆的异常。

根据您的编辑,您可能在投掷“按指针”和捕获“按引用”之间不匹配。如果您已经解决了这个问题并且仍未执行catch块,则可以尝试使用CRT SetAbortHandler来调试abort()调用以安装您自己的中止函数。这可以简单地链接到现有的一个,但是可以设置一个断点并检查调用堆栈以查看出错的地方。

答案 2 :(得分:1)

C ++ try-catch-throw逻辑用于假人。请注意,这不包括基于RAII /堆栈的分配/销毁。

  • 当您抛出异常时,异常被称为“传播”。它向上传播调用堆栈,直到找到第一个可以处理它的处理程序(因此它被捕获)或者直到它到达调用堆栈的根目录。
    • 如果被捕获,则从捕获异常的点继续执行。该异常在catch块的末尾被破坏。
    • 如果找到根,则调用std :: unhandled_exception,它通常调用std :: terminate,它通常调用abort()。简而言之,一切都在尽快下降。
  • 如果在异常当前正在传播时抛出异常,则一次有两个传播。 Java和C#有很好的处理方式,但这应该永远不会发生 - 没有异常处理程序在逻辑上处理异常组合。当一个当前正在传播时,不要抛出异常。即使你不使用不应该使用的std :: uncaught_exception(),这个规则也难以持有。
  • 在展开堆栈/传播异常时,会破坏堆栈中找到的所有对象。这些析构函数永远不应该抛出异常 - 毕竟,当破坏对象“失败”时,在析构函数修复它之后你还要做什么呢?
  • 始终按价值投掷,以引用方式捕获。如果你抛出&amp;通过指针捕获,你很可能会泄漏一些东西,这是不可能的参考。如果按值捕获,则会切除派生的异常类型。抓住参考。
  • 在软件的根目录中,包括一个全能 - catch(...)。这不允许你找出你到底抓到了什么,但至少你可以安全地坠毁。当被调用的代码可能抛出你不知道的“东西”时,也要这样做。