C++;捕获所有异常 是否存在C++的等价于java的< /p> try { ... } catch (Throwable t) { ... }

C++;捕获所有异常 是否存在C++的等价于java的< /p> try { ... } catch (Throwable t) { ... },c++,exception,C++,Exception,我正在尝试调试调用本机windows函数的Java/jni代码,而虚拟机一直在崩溃。本机代码在单元测试中表现良好,只有在通过jni调用时才会崩溃。通用异常捕获机制将被证明非常有用 try { // ... } catch (...) { // ... } 请注意,catch中的…是一个真正的省略号,即三个点 但是,由于C++异常不一定是BASE异常< /代码>类的子类,所以没有任何方法可以真正看到使用此构造时抛出的异常变量。 < P>可以使用< /P> catch(...) 但这

我正在尝试调试调用本机windows函数的Java/jni代码,而虚拟机一直在崩溃。本机代码在单元测试中表现良好,只有在通过jni调用时才会崩溃。通用异常捕获机制将被证明非常有用

try {
   // ...
} catch (...) {
   // ...
}
请注意,
catch
中的
是一个真正的省略号,即三个点

但是,由于C++异常不一定是BASE<代码>异常< /代码>类的子类,所以没有任何方法可以真正看到使用此构造时抛出的异常变量。

< P>可以使用< /P>
catch(...)
但这是非常危险的。在他的书中,约翰·罗宾斯讲述了一个战争故事,讲述了一只被捕杀(…)命令掩盖的讨厌的虫子。捕捉特定的异常会更好。捕获您认为try块可能合理抛出的任何内容,但如果发生了真正意想不到的事情,则让代码抛出更高级别的异常

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

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

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

让我在这里提一下:Java

try 
{
...
}
catch (Exception e)
{
...
}
可能无法捕获所有异常!事实上,我以前也有过类似的事情发生过,这很让人发疯;异常源于Throwable。所以从字面上说,要捕获所有内容,您不希望捕获异常;你想抓住抛弃者

我知道这听起来很挑剔,但是当你花了几天的时间试图找出“未捕获异常”在被try包围的代码中的来源时。。。捕捉(例外情况e)“块来自,它会粘住你

一种通用的异常捕获机制 这将证明非常有用

try {
   // ...
} catch (...) {
   // ...
}
怀疑。你已经知道你的代码被破坏了,因为它正在崩溃。吃异常可能会掩盖这一点,但这可能只会导致更糟糕、更微妙的错误


您真正想要的是一个调试器…

应该有人添加一个无法捕获“崩溃”的调试器“在C++代码中。这些不会抛出异常,但可以做任何他们喜欢的事情。当你看到一个程序因为一个空指针取消引用而崩溃时,它正在做未定义的行为。没有
std::null\u指针\u异常
。试图捕获异常在这方面没有帮助

如果有人正在阅读此线程,并认为他可以找到程序崩溃的原因。应该改用gdb之类的调试器

  • 您是否可以从控制台窗口(从Java命令行启动)使用Java应用程序运行JNI,以查看是否存在JVM崩溃前检测到的任何报告。当直接作为Java窗口应用程序运行时,可能会丢失从控制台窗口运行时会显示的消息

  • 第二,你能存根你的JNIDLL实现来显示你的DLL中的方法是从JNI输入的,你是正确返回的,等等吗

  • <> L> >如果问题是从C++代码中错误地使用JNI接口方法之一,你是否验证了一些简单的JNI示例编译并与安装程序一起工作?我特别想使用JNI接口方法来将参数转换为本机C++格式,并将函数结果转换为java类型。对这些进行存根是很有用的,以确保数据转换正在工作,并且不会在对JNI接口进行类似COM的调用时失控

  • 还有其他事情需要检查,但是如果不了解更多关于本机Java方法是什么以及它们的JNI实现试图做什么的信息,就很难提出任何建议。不清楚从C++代码级别捕获异常与您的问题有关。(您可以使用JNI接口将异常作为Java异常重新抛出,但从您提供的内容来看,这是否有帮助还不清楚。)

  • (在C++中)不可能以可移植的方式捕获所有异常。这是因为一些异常在C++上下文中不是例外。这包括零误差除法等。当这些错误发生时,可以进行黑客攻击,从而获得抛出异常的能力,但这并不容易做到,而且以一种可移植的方式纠正也不容易

    如果您想捕获所有STL异常,可以这样做

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


    如果有人愚蠢到抛出一个不是继承自
    std::exception

    的异常,这对您没有帮助,因为真正的问题是无法正确调试使用JNI的程序(或者在调试器下运行时没有出现错误):

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

    这通常比在本机调试中调试大规模并行Java程序更容易找到真正的错误(令人惊讶的是,大部分错误出现在不遵守被调用函数语义的Java代码中,导致了一些令人讨厌的双重释放或类似错误)
    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
    }
    
    #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;
    }
    
    catch (...)
    {
        std::clog << boost::current_exception_diagnostic_information() << std::endl;
    }
    
     SEH exception
     terminate
     unexpected
     pure virtual method call
     invalid parameter
     new operator fault 
     SIGABR
     SIGFPE
     SIGILL
     SIGINT
     SIGSEGV
     SIGTERM
     Raised exception
    C++ typed exception
    
    try{
    // ...
    } catch (...) {
    // ...
    }