简体   繁体   English

C++ 捕获所有异常

[英]C++ catching all exceptions

Is there a c++ equivalent of Java's是否有 C++ 等价于 Java 的

try {
    ...
}
catch (Throwable t) {
    ...
}

I am trying to debug Java/jni code that calls native windows functions and the virtual machine keeps crashing.我正在尝试调试调用本机 Windows 函数的 Java/jni 代码,但虚拟机不断崩溃。 The native code appears fine in unit testing and only seems to crash when called through jni.本机代码在单元测试中看起来很好,只有在通过 jni 调用时才会崩溃。 A generic exception catching mechanism would prove extremely useful.通用的异常捕获机制将证明非常有用。

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

will catch all C++ exceptions, but it should be considered bad design.将捕获所有 C++ 异常,但它应该被认为是糟糕的设计。 You can use c++11's new current_exception mechanism, but if you don't have the ability to use c++11 (legacy code systems requiring a rewrite), then you have no named exception pointer to use to get a message or name.您可以使用 c++11 的新 current_exception 机制,但是如果您没有能力使用 c++11(需要重写的遗留代码系统),那么您就没有用于获取消息或名称的命名异常指针. You may want to add separate catch clauses for the various exceptions you can catch, and only catch everything at the bottom to record an unexpected exception.您可能希望为您可以捕获的各种异常添加单独的 catch 子句,并且只捕获底部的所有内容以记录意外异常。 Eg:例如:

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

Someone should add that one cannot catch "crashes" in C++ code.有人应该补充一点,不能在 C++ 代码中捕获“崩溃”。 Those don't throw exceptions, but do anything they like.那些不会抛出异常,而是做任何他们喜欢的事情。 When you see a program crashing because of say a null-pointer dereference, it's doing undefined behavior.当您看到程序因为空指针取消引用而崩溃时,它正在执行未定义的行为。 There is no std::null_pointer_exception .没有std::null_pointer_exception Trying to catch exceptions won't help there.试图捕捉异常在那里无济于事。

Just for the case someone is reading this thread and thinks he can get the cause of the program crashes.只是因为有人正在阅读这个线程并认为他可以找到程序崩溃的原因。 A Debugger like gdb should be used instead.应该使用像 gdb 这样的调试器。

This is how you can reverse-engineer the exception type from within catch(...) should you need to (may be useful when catching unknown from a third party library) with GCC:如果您需要(从第三方库中捕获未知时可能很有用catch(...) ,您可以使用 GCC 从catch(...)对异常类型进行逆向工程:

#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;
}

and if you can afford using Boost you can make your catch section even simpler (on the outside) and potentially cross-platform如果您负担得起使用Boost,您可以使您的捕获部分更加简单(在外部)并且可能是跨平台的

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

Note that the ... inside the catch is a real ellipsis, ie.请注意, catch中的...是一个真正的省略号,即。 three dots.三个点。

However, because C++ exceptions are not necessarily subclasses of a base Exception class, there isn't any way to actually see the exception variable that is thrown when using this construct.但是,因为 C++ 异常不一定是基础Exception类的子类,所以没有任何方法可以实际查看使用此构造时抛出的异常变量。

it is not possible (in C++) to catch all exceptions in a portable manner.不可能(在 C++ 中)以可移植的方式捕获所有异常。 This is because some exceptions are not exceptions in a C++ context.这是因为某些异常不是 C++ 上下文中的异常。 This includes things like division by zero errors and others.这包括除以零错误等内容。 It is possible to hack about and thus get the ability to throw exceptions when these errors happen, but it's not easy to do and certainly not easy to get right in a portable manner.当这些错误发生时,有可能破解并因此获得抛出异常的能力,但这并不容易,当然也不容易以可移植的方式正确。

If you want to catch all STL exceptions, you can do如果要捕获所有 STL 异常,可以执行

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

Which will allow you do use e.what() , which will return a const char* , which can tell you more about the exception itself.这将允许您使用e.what() ,它将返回一个const char* ,它可以告诉您有关异常本身的更多信息。 This is the construct that resembles the Java construct, you asked about, the most.这是最类似于 Java 构造的构造,你问过,最。

This will not help you if someone is stupid enough to throw an exception that does not inherit from std::exception .如果有人愚蠢到抛出不是从std::exception继承的异常,这将无济于事。

In short, use catch(...) .简而言之,使用catch(...) However, note that catch(...) is meant to be used in conjunction with throw;但是,请注意catch(...)旨在与throw;结合使用throw; basically:基本上:

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
}

This is the proper way to use catch(...) .这是使用catch(...)的正确方法。

it is possible to do this by writing:可以这样写:

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

But there is a very not noticeable risk here: you can not find the exact type of error that has been thrown in the try block, so use this kind of catch when you are sure that no matter what the type of exception is, the program must persist in the way defined in the catch block.但是这里有一个非常不明显的风险:你无法找到try块中抛出的确切类型的错误,所以当你确定不管是什么类型的异常,程序时使用这种catch必须以catch块中定义的方式持久化。

You can use您可以使用

catch(...)

but that is very dangerous.但这是非常危险的。 In his book Debugging Windows , John Robbins tells a war story about a really nasty bug that was masked by a catch(...) command.在他的Debugging Windows一书中,John Robbins 讲述了一个关于被 catch(...) 命令掩盖的非常讨厌的错误的战争故事。 You're much better off catching specific exceptions.你最好捕捉特定的异常。 Catch whatever you think your try block might reasonably throw, but let the code throw an exception higher up if something really unexpected happens.捕获您认为 try 块可能合理抛出的任何内容,但如果确实发生了意外情况,请让代码向上抛出异常。

Let me just mention this here: the Java让我在这里提一下:Java

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

may NOT catch all exceptions!可能无法捕获所有异常! I've actually had this sort of thing happen before, and it's insantiy-provoking;我以前也遇到过这样的事情,真是发人深省; Exception derives from Throwable.异常源自 Throwable。 So literally, to catch everything, you DON'T want to catch Exceptions;所以从字面上看,要捕获所有内容,您不想捕获异常; you want to catch Throwable.你想抓住 Throwable。

I know it sounds nitpicky, but when you've spent several days trying to figure out where the "uncaught exception" came from in code that was surrounded by a try ... catch (Exception e)" block comes from, it sticks with you.我知道这听起来很挑剔,但是当您花了几天时间试图找出被 try ... catch (Exception e)" 块包围的代码中“未捕获的异常”来自哪里时,它坚持你。

Well, if you would like to catch all exception to create a minidump for example...好吧,如果您想捕获所有异常以创建小型转储,例如...

Somebody did the work on Windows.有人在 Windows 上完成了这项工作。

See http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus In the article, he explains how he found out how to catch all kind of exceptions and he provides code that works.请参阅http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus在文章中,他解释了他如何发现如何捕获所有类型的异常,并提供了有效的代码。

Here is the list you can catch:这是您可以捕获的列表:

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

And the usage: CCrashHandler ch;以及用法:CCrashHandler ch; ch.SetProcessExceptionHandlers(); ch.SetProcessExceptionHandlers(); // do this for one thread ch.SetThreadExceptionHandlers(); // 为一个线程执行此操作 ch.SetThreadExceptionHandlers(); // for each thred // 对于每个线程


By default, this creates a minidump in the current directory (crashdump.dmp)默认情况下,这会在当前目录 (crashdump.dmp) 中创建一个小型转储

Be aware意识到

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

catches only language-level exceptions, other low-level exceptions/errors like Access Violation and Segmentation Fault wont be caught.仅捕获语言级异常,不会捕获其他低级异常/错误,如Access ViolationSegmentation Fault

A generic exception catching mechanism would prove extremely useful.通用的异常捕获机制将证明非常有用。

Doubtful.疑。 You already know your code is broken, because it's crashing.您已经知道您的代码已损坏,因为它正在崩溃。 Eating exceptions may mask this, but that'll probably just result in even nastier, more subtle bugs.饮食异常可能会掩盖这一点,但这可能只会导致更讨厌、更微妙的错误。

What you really want is a debugger...你真正想要的是一个调试器......

  1. Can you run your JNI-using Java application from a console window (launch it from a java command line) to see if there is any report of what may have been detected before the JVM was crashed.您能否从控制台窗口运行使用 JNI 的 Java 应用程序(从 Java 命令行启动它),以查看是否有任何关于在 JVM 崩溃之前可能检测到的内容的报告。 When running directly as a Java window application, you may be missing messages that would appear if you ran from a console window instead.当直接作为 Java 窗口应用程序运行时,您可能会丢失从控制台窗口运行时会出现的消息。

  2. Secondly, can you stub your JNI DLL implementation to show that methods in your DLL are being entered from JNI, you are returning properly, etc?其次,您能否存根您的 JNI DLL 实现以显示您的 DLL 中的方法是从 JNI 输入的,您正在正确返回等?

  3. Just in case the problem is with an incorrect use of one of the JNI-interface methods from the C++ code, have you verified that some simple JNI examples compile and work with your setup?万一问题出在错误使用 C++ 代码中的 JNI 接口方法之一,您是否验证了一些简单的 JNI 示例可以编译并与您的设置一起使用? I'm thinking in particular of using the JNI-interface methods for converting parameters to native C++ formats and turning function results into Java types.我特别考虑使用 JNI 接口方法将参数转换为原生 C++ 格式并将函数结果转换为 Java 类型。 It is useful to stub those to make sure that the data conversions are working and you are not going haywire in the COM-like calls into the JNI interface.对那些进行存根以确保数据转换正常工作并且您不会在类 COM 调用 JNI 接口中陷入混乱是很有用的。

  4. There are other things to check, but it is hard to suggest any without knowing more about what your native Java methods are and what the JNI implementation of them is trying to do.还有其他事情要检查,但是如果不了解更多关于您的本机 Java 方法是什么以及它们的 JNI 实现正在尝试做什么,就很难提出任何建议。 It is not clear that catching an exception from the C++ code level is related to your problem.目前尚不清楚从 C++ 代码级别捕获异常是否与您的问题有关。 (You can use the JNI interface to rethrow the exception as a Java one, but it is not clear from what you provide that this is going to help.) (您可以使用 JNI 接口将异常作为 Java 接口重新抛出,但从您提供的内容中不清楚这是否会有所帮助。)

For the real problem about being unable to properly debug a program that uses JNI (or the bug does not appear when running it under a debugger):对于无法正确调试使用 JNI 的程序的真正问题(或在调试器下运行时不会出现错误):

In this case it often helps to add Java wrappers around your JNI calls (ie all native methods are private and your public methods in the class call them) that do some basic sanity checking (check that all "objects" are freed and "objects" are not used after freeing) or synchronization (just synchronize all methods from one DLL to a single object instance).在这种情况下,通常有助于在 JNI 调用周围添加 Java 包装器(即所有本机方法都是私有的,类中的公共方法调用它们)进行一些基本的健全性检查(检查所有“对象”是否已释放,“对象”释放后不使用)或同步(只是将所有方法从一个 DLL 同步到单个对象实例)。 Let the java wrapper methods log the mistake and throw an exception.让 java 包装器方法记录错误并抛出异常。

This will often help to find the real error (which surprisingly is mostly in the Java code that does not obey the semantics of the called functions causing some nasty double-frees or similar) more easily than trying to debug a massively parallel Java program in a native debugger...这通常有助于找到真正的错误(令人惊讶的是,这主要是在 Java 代码中,它不遵守被调用函数的语义,导致一些令人讨厌的双重释放或类似的问题)比尝试在一个大规模并行 Java 程序中调试更容易本机调试器...

If you know the cause, keep the code in your wrapper methods that avoids it.如果您知道原因,请将代码保留在您的包装方法中以避免它。 Better have your wrapper methods throw exceptions than your JNI code crash the VM...最好让您的包装器方法抛出异常,而不是您的 JNI 代码使 VM 崩溃...

Well this really depends on the compiler environment.嗯,这真的取决于编译器环境。 gcc does not catch these. gcc 没有捕捉到这些。 Visual Studio and the last Borland that I used did. Visual Studio 和我使用的最后一个 Borland 做到了。

So the conclusion about crashes is that it depends on the quality of your development environment.所以关于崩溃的结论是它取决于你的开发环境的质量。

The C++ specification says that catch(...) must catch any exceptions, but it doesn't in all cases. C++ 规范说 catch(...) 必须捕获任何异常,但并非在所有情况下都如此。

At least from what I tried.至少从我的尝试来看。

If you are looking for Windows-specific solution then there is structured exception handling : https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement如果您正在寻找特定Windows 的解决方案,那么结构化异常处理https : //docs.microsoft.com/en-us/cpp/cpp/try-except-statement

The code looks as follows代码如下

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

It will catch not only C++ exceptions but also access violations or other system exceptions.它不仅会捕获 C++ 异常,还会捕获访问冲突或其他系统异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM