C ++捕获所有异常

时间:2008-11-25 00:11:11

标签: c++ exception

是否有类似Java的

的c ++
try {
    ...
}
catch (Throwable t) {
    ...
}

我正在尝试调试调用本机Windows函数的Java / jni代码,并且虚拟机不断崩溃。本机代码在单元测试中看起来很好,并且在通过jni调用时似乎只会崩溃。一般的异常捕获机制将非常有用。

16 个答案:

答案 0 :(得分:299)

try{
    // ...
} catch (...) {
    // ...
}

将捕获所有C ++异常,但它应被视为糟糕的设计。您可以使用c ++ 11的新current_exception机制,但如果您无法使用c ++ 11(需要重写的遗留代码系统),那么您没有用于获取消息或名称的命名异常指针。您可能希望为可捕获的各种异常添加单独的catch子句,并且只捕获底部的所有内容以记录意外异常。 E.g:

try{
    // ...
} catch (const std::exception& ex) {
    // ...
} catch (const std::string& ex) {
    // ...
} catch (...) {
    // ...
}

答案 1 :(得分:127)

有人应该补充说,在C ++代码中无法捕获“崩溃”。那些不会抛出异常,而是做任何他们喜欢的事情。当你看到程序因为空指针解除引用而崩溃时,它正在做未定义的行为。没有std::null_pointer_exception。试图捕捉异常对那里没有帮助。

只是有人正在阅读这个帖子,并认为他可以解决程序崩溃的原因。应该使用像gdb这样的调试器。

答案 2 :(得分:56)

try {
   // ...
} catch (...) {
   // ...
}

请注意...内的catch是一个真正的省略号,即。三点。

但是,因为C ++异常不一定是基类Exception类的子类,所以没有任何方法可以实际看到使用此构造时抛出的异常变量。

答案 3 :(得分:49)

如果您需要(在从第三方库中捕获未知时可能很有用),您可以从catch(...)内对异常类型进行反向工程:G / C

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}

如果你能负担得起Boost,你可以让你的捕捉部分更简单(在外面)和潜在的跨平台

catch (...)
{
    std::clog << boost::current_exception_diagnostic_information() << std::endl;
}

答案 4 :(得分:34)

不可能(在C ++中)以可移植的方式捕获所有异常。这是因为某些异常在C ++上下文中不是异常。这包括除零错误等等。当这些错误发生时,有可能破解并因此获得抛出异常的能力,但这样做并不容易,并且当然不容易以可移植的方式正确。

如果要捕获所有STL异常,可以执行

try { ... } catch( const std::exception &e) { ... }

这将允许您使用e.what(),它将返回const char*,它可以告诉您有关异常本身的更多信息。这是一个类似于Java构造的构造,你问的最多。

如果有人愚蠢地抛出不从std::exception继承的异常,这对你没有帮助。

答案 5 :(得分:21)

简而言之,请使用catch(...)。但请注意,catch(...)基本上应与throw;结合使用:

try{
    foo = new Foo;
    bar = new Bar;
}
catch(...)       // will catch all possible errors thrown. 
{ 
    delete foo;
    delete bar;
    throw;       // throw the same error again to be handled somewhere else
}

这是使用catch(...)的正确方法。

答案 6 :(得分:18)

可以通过写:

来做到这一点
try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

但是这里存在一个非常明显的风险:您无法找到try块中引发的确切错误类型,因此当您确定时,请使用此类catch无论什么类型的异常,程序必须以catch块中定义的方式保持。

答案 7 :(得分:17)

您可以使用

catch(...)

但这非常危险。约翰罗宾斯在他的书Debugging Windows中讲述了一个关于一个非常令人讨厌的错误的战争故事,这个错误被一个catch(...)命令掩盖了。捕获特定异常会更好。抓住你认为你的try块可能合理抛出的任何东西,但如果发生了意想不到的事情,让代码抛出更高的异常。

答案 8 :(得分:12)

我在这里提一下:Java

try 
{
...
}
catch (Exception e)
{
...
}

可能无法捕获所有异常!事实上,我之前已经发生过这样的事情,而且这是令人厌恶的;异常来自Throwable。从字面上看,要抓住一切,你不要想抓住例外;你想抓住Throwable。

我知道这听起来很挑剔,但是当你花了几天的时间试图找出“未捕获的异常”来自代码的地方时,其中包含了一个try ... catch(异常e)“块来自,它坚持你。

答案 9 :(得分:7)

好吧,如果您想捕获所有例外来创建一个minidump,例如......

有人在Windows上完成了这项工作。

参见http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus 在文章中,他解释了他如何发现如何捕获所有类型的异常,并提供可行的代码。

以下是您可以捕获的列表:

 SEH exception
 terminate
 unexpected
 pure virtual method call
 invalid parameter
 new operator fault 
 SIGABR
 SIGFPE
 SIGILL
 SIGINT
 SIGSEGV
 SIGTERM
 Raised exception
C++ typed exception

用法: CCrashHandler ch; ch.SetProcessExceptionHandlers(); //为一个线程执行此操作 ch.SetThreadExceptionHandlers(); //为每个thred


默认情况下,这会在当前目录(crashdump.dmp)中创建一个minidump

答案 10 :(得分:4)

  

通用异常捕获机制   会证明非常有用。

疑。你已经知道你的代码坏了,因为它崩溃了。吃异常可能会掩盖这一点,但这可能只会导致更糟糕,更微妙的错误。

你真正想要的是一个调试器......

答案 11 :(得分:2)

  1. 您是否可以从控制台窗口运行使用JNI的Java应用程序(从java命令行启动它),以查看是否有任何关于在JVM崩溃之前可能检测到的内容的报告。直接作为Java窗口应用程序运行时,如果从控制台窗口运行,则可能会丢失显示的消息。

  2. 其次,您可以存根JNI DLL实现,以显示您的DLL中的方法是从JNI输入的,您是否正确返回等等?

  3. 如果问题是错误地使用了C ++代码中的一个JNI接口方法,您是否已经验证了一些简单的JNI示例是否可以编译并使用您的设置?我正在考虑使用JNI接口方法将参数转换为本机C ++格式并将函数结果转换为Java类型。保留这些数据以确保数据转换正常工作并且在类似COM的JNI接口调用中不会出现问题是非常有用的。

  4. 还有其他事情需要检查,但如果不了解更多有关您的本机Java方法以及它们正在尝试执行的JNI实现的内容,则很难建议。目前尚不清楚从C ++代码级别捕获异常与您的问题有关。 (您可以使用JNI接口将异常重新抛出为Java,但不清楚您提供的内容是否有帮助。)

答案 12 :(得分:2)

注意

try{
// ...
} catch (...) {
// ...
}

仅捕获语言级别的异常,不会捕获其他低级别的异常/错误,例如Access ViolationSegmentation Fault

答案 13 :(得分:1)

关于无法正确调试使用JNI的程序的真正问题(或者在调试器下运行时不会出现错误):

在这种情况下,通常有助于在JNI调用周围添加Java包装器(即所有本机方法都是私有的,并且类中的公共方法调用它们),这些方法执行一些基本的健全性检查(检查所有“对象”是否已释放,以及释放后不使用“对象”或同步(只是将所有方法从一个DLL同步到单个对象实例)。让java包装器方法记录错误并抛出异常。

这通常会比试图调试大规模并行Java更容易找到真正的错误(令人惊讶地主要是在Java代码中不遵守被调用函数的语义导致一些讨厌的双重释放或类似)本机调试器中的程序......

如果您知道原因,请将代码保留在包装器方法中以避免它。最好让你的包装器方法抛出异常而不是你的JNI代码崩溃VM ...

答案 14 :(得分:0)

这真的取决于编译环境。 gcc没有抓住这些。 Visual Studio和我用过的最后一个Borland。

因此,关于崩溃的结论是它取决于您的开发环境的质量。

C ++ 规范说catch(...)必须捕获任何异常,但并非在所有情况下都是如此。

至少从我的尝试开始。

答案 15 :(得分:0)

如果您正在寻找特定于 Windows 的解决方案,那么有结构化异常处理https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement

代码如下

__try
{
   // code here may throw or make access violation
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
    // after exception code here, e.g. log the error
}

它不仅会捕获 C++ 异常,还会捕获访问冲突或其他系统异常。