捕获未知异常
Posted
技术标签:
【中文标题】捕获未知异常【英文标题】:catching unknown exception 【发布时间】:2011-07-08 13:21:43 【问题描述】:在我的代码的发布版本中,有一行抛出异常,我不知道它是什么类型的异常,所以我无法正确捕获它或找出问题所在。
我使用了 catch(...) 但这几乎毫无价值。
这是一些伪代码
try
m_mmwIPC = gcnew NiftyIPC(gcnew String("Monitor"), true);
catch (CException* e)
TCHAR szCause[255];
e->GetErrorMessage(szCause, 255);
CString errorStr = szCause;
RemoveLineFeeds(errorStr);
OutputDebugString(errorStr);
catch(...)
OutputDebugString(L"Unknown exception\n");
那么,有什么方法可以获取有关引发的未知异常的任何详细信息?只是一个类型就很好了。
谢谢
【问题讨论】:
(我的脑海里突然闪过一个偶然的想法)很遗憾,C++0xauto
的措辞是“从它的 initializer 中扣除的”,而且那里尽管类型对编译器来说或多或少是显而易见的,但这里确实不是初始化器。否则可以写catch(auto excpt)
。当然,对于必须生成所有这些单独的代码路径的编译器来说,这可能是一个巨大的负担......
【参考方案1】:
不是真的,它可能是 int
、const char*
或 RhubarbPie
über-smart 指针。
但是:
也尝试捕捉std::exception
。这将捕获大量 C++ 原生异常。
您的异常可能是 .NET 异常,因此请尝试捕获该异常,而不是 MFC 基础异常。 (看起来您正在使用 C++/CLI。在这种情况下,.NET 异常最终会出现在 catch-all 子句中)
此外,异常通常意味着在 C++ 中通过引用来捕获
(更新:MFC 显然通过指针使用 throw-and-catch。只要你捕捉到抛出的东西,它也可以工作。)
使用 __try 和 __catch 也可能会有所帮助,因为堆栈溢出、访问冲突等一些“硬件”异常在 Windows 上也是未知异常。捕获它们的语法略有不同,但您会得到一个异常标识符,可用于报告引发的异常类型。我用它来打印我们应用程序中致命错误的堆栈跟踪。
【讨论】:
尽管在 C++ 中通过引用更好地捕获是公平的,但我相信 MFC 倾向于遵循通过指针捕获的约定。这并不能阻止用户代码通过引用来捕获。 我认为这是我能做的最好的方法。尝试捕获所有泛型类型并尽我所能记录它们。 MFC 确实通过指针捕获,但这并不重要,因为在幕后引用只是一个指针。 @lunknown:好的。我不知道MFC。请注意,对 X 的引用和指向 X 的指针是与编译器无关的两种类型,因此 catch() 子句不会自动转换。如果异常是由指针引发的,则需要通过指针捕获,或者如果由值(或引用,我想)抛出,则需要通过引用捕获。【参考方案2】:当您指定使用 MFC 时,我将假设您使用的是 Visual Studio 版本。如果是这种情况并且您能够在调试模式下运行程序,那么您可以将调试器设置为在未处理的异常上中断。这需要删除代码的catch(...)
部分,但它应该在正确的位置进入调试器,并为您提供有关异常本身的有用信息。
请参阅 Microsoft 文档 here 和 here。
【讨论】:
该异常仅在发布模式下发生,就像我似乎发现的所有丑陋错误一样。 @luknown:您可以在发布模式代码上运行调试器(尤其是如果您使用调试信息构建)。只是不要期望调试器在调试优化代码时正确报告堆栈上的值。【参考方案3】:每个异常都应该派生自std::exception
,然后您可以使用 RTTI。标准的 catch 块是
catch (const std :: exception & e)
// e .what ();
// typeid (e);
catch (...)
// WTF ?!?!?
在 c++0x 中,您可以使用 std::current_exception
并可能将 exception_ptr
传递到一些聪明的库中进行分析。
请记住,异常可以是 buildins 和其他没有 RTTI 的类型,这就是为什么您应该始终从 std::exception 派生的原因。
【讨论】:
"每个异常都应该从 std::exception 派生":MFC 就是这种情况吗?我知道 CException 派生自 CObject - 它也派生自 std::exception 吗? 可能但不是必须的。检查NULL != dynamic_cast<const std::exception *>(CExecption_pointer)
实际上,如果你有上面的 catch 块,当且仅当它派生自 std::exception 时,你的 CException 对象才会绑定到它(并且如果没有更具体的匹配块首先潜入)
【参考方案4】:
不,这里不是。 catch( ...) 真的应该作为最后的手段使用。
【讨论】:
【参考方案5】:一种选择是不捕获错误并在调试器中运行程序员(这在发布模式下是可能的)。 Visual Studio 将闯入发生未捕获异常的代码。
【讨论】:
以上是关于捕获未知异常的主要内容,如果未能解决你的问题,请参考以下文章