2013-04-26 97 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(...)。这不能让你发现你到底抓到了什么,但至少你可以安全地坠毁。当被调用的代码可能抛出你不知道的“某些东西”时,也要这样做。
相关问题