当我抛出一个C++;来自本机Java方法的异常? 假设我将Sun的JVM嵌入C++应用程序中。通过JNI,我调用一个Java方法(我自己的),它反过来调用我在共享库中实现的本机方法 如果这个原生方法抛出C++异常,那么会发生什么?

当我抛出一个C++;来自本机Java方法的异常? 假设我将Sun的JVM嵌入C++应用程序中。通过JNI,我调用一个Java方法(我自己的),它反过来调用我在共享库中实现的本机方法 如果这个原生方法抛出C++异常,那么会发生什么?,java,c++,linux,exception,java-native-interface,Java,C++,Linux,Exception,Java Native Interface,编辑:编译器是gcc 3.4.x,jvm是sun的1.6.20。我猜你的jvm会崩溃。本地C++异常不会通过JNI传播到java。其中一个原因是JNI是C接口,C对C++异常一无所知。p> 你必须做的是在进入JNI代码的C层之前捕获C++异常,并使JNI- C函数返回错误代码。然后,您可以检查Java内部的错误代码,并在必要时抛出Java异常。我会将其标记为未定义的行为。将异常传播回C代码(即运行JVM的代码)是未定义的行为 在Windows上,编译器必须使用微软的结构化异常处理来实现异常,因此

编辑:编译器是gcc 3.4.x,jvm是sun的1.6.20。

我猜你的jvm会崩溃。本地C++异常不会通过JNI传播到java。其中一个原因是JNI是C接口,C对C++异常一无所知。p>
<>你必须做的是在进入JNI代码的C层之前捕获C++异常,并使JNI- C函数返回错误代码。然后,您可以检查Java内部的错误代码,并在必要时抛出Java异常。

我会将其标记为未定义的行为。将异常传播回C代码(即运行JVM的代码)是未定义的行为

在Windows上,编译器必须使用微软的结构化异常处理来实现异常,因此C++异常将通过C代码安全地被捕获。strong>但是,C代码并不是在编写时考虑到异常的,因此,如果幸运的话,您会遇到崩溃,如果不幸运的话,则会出现不一致的状态和资源泄漏


在其他平台上,我不知道,但再漂亮不过了。当我编写JNI代码时,我将每个C++函数封装在一个<代码>尝试< /Cube >块中:即使我没有<代码>抛出< /C> >,我仍然可能会得到一些标准的异常( STD::BADYOLLC/),但是其他的也是可能的。p> 在JNI文献中,异常一词似乎专门用来指Java异常。本机代码中的意外事件称为编程错误。JNI明确地不要求JVM检查编程错误。如果发生编程错误,则行为未定义。不同的JVM可能表现不同


本机代码负责将所有编程错误转换为返回代码或Java异常。Java异常不会立即从本机代码中抛出。它们可以挂起,只有在本机代码返回Java调用方时才会抛出。本机代码可以使用
ExceptionOccurred
检查挂起的异常,并使用
ExceptionClear
清除它们。JNI使用c函数与本机代码进行接口。C无法正确处理异常,因为它不知道异常的存在。因此,您必须捕获本机代码中的异常并将其转换为java异常,否则jvm将崩溃。(java java java)异常,因为Java异常只在原生代码返回Java之后才被抛出)

,java编译器不理解C++异常,所以你必须同时使用Java和C++异常。幸运的是,这并不太复杂。首先,我们有一个C++异常,告诉我们是否发生了java异常。
#include <stdexcept>
//This is how we represent a Java exception already in progress
struct ThrownJavaException : std::runtime_error {
    ThrownJavaException() :std::runtime_error("") {}
    ThrownJavaException(const std::string& msg ) :std::runtime_error(msg) {}
};

我们也有一个C++异常来抛出新的java异常:

//used to throw a new Java exception. use full paths like:
//"java/lang/NoSuchFieldException"
//"java/lang/NullPointerException"
//"java/security/InvalidParameterException"
struct NewJavaException : public ThrownJavaException{
    NewJavaException(JNIEnv * env, const char* type="", const char* message="")
        :ThrownJavaException(type+std::string(" ")+message)
    {
        jclass newExcCls = env->FindClass(type);
        if (newExcCls != NULL)
            env->ThrowNew(newExcCls, message);
        //if it is null, a NoClassDefFoundError was already thrown
    }
};

我们还需要一个函数来吞入C++异常,用java异常< /p>替换它们。

void swallow_cpp_exception_and_throw_java(JNIEnv * env) {
    try {
        throw;
    } catch(const ThrownJavaException&) {
        //already reported to Java, ignore
    } catch(const std::bad_alloc& rhs) {
        //translate OOM C++ exception to a Java exception
        NewJavaException(env, "java/lang/OutOfMemoryError", rhs.what()); 
    } catch(const std::ios_base::failure& rhs) { //sample translation
        //translate IO C++ exception to a Java exception
        NewJavaException(env, "java/io/IOException", rhs.what()); 

    //TRANSLATE ANY OTHER C++ EXCEPTIONS TO JAVA EXCEPTIONS HERE

    } catch(const std::exception& e) {
        //translate unknown C++ exception to a Java exception
        NewJavaException(env, "java/lang/Error", e.what());
    } catch(...) {
        //translate unknown C++ exception to a Java exception
        NewJavaException(env, "java/lang/Error", "Unknown exception type");
    }
}

以上功能,在C++代码中很容易使用java/C++混合异常,如下所示。

extern "C" JNIEXPORT 
void JNICALL Java_MyClass_MyFunc(JNIEnv * env, jclass jc_, jstring param)
{
    try { //do not let C++ exceptions outside of this function

        //YOUR CODE BELOW THIS LINE.  HERES SOME RANDOM CODE
        if (param == NULL) //if something is wrong, throw a java exception
             throw NewJavaException(env, "java/lang/NullPointerException", "param");            
        do_stuff(param); //might throw java or C++ exceptions
        assert_no_exception(env); //throw a C++ exception if theres a java exception
        do_more_stuff(param); //might throw C++ exceptions
        //prefer Java exceptions where possible:
        if (condition1) throw NewJavaException(env, "java/lang/NullPointerException", "condition1");
        //but C++ exceptions should be fine too
        if (condition0) throw std::bad_alloc("BAD_ALLOC");
        //YOUR CODE ABOVE THIS LINE.  HERES SOME RANDOM CODE

    } catch(...) { //do not let C++ exceptions outside of this function
        swallow_cpp_exception_and_throw_java(env);
    } 

}

如果您真的很有野心,那么可以跟踪较大函数的
StackTraceElement[]
,并获得部分stacktrace。基本方法是给每个函数一个
stackTraceeElement
,在调用它们时,将指向它们的指针推到线程本地“callstack”上,当它们返回时,将指针弹出。然后,改变
NewJavaException
的构造函数来制作该堆栈的副本,并将其传递给
setStackTrace

如果让它向上传播,那么可能会得到VM“恐慌”响应。为什么不试试呢?什么平台?可能是编译器特定的……米迦勒:我认为“java”是一个平台?java SBjava不是一个你可以运行C++的平台。你可以用SpEn新建函数在本地代码中抛出Java异常。当存在java风格的解决方案时,不需要添加错误代码。您是对的。我不知道ThrowNew的事。但是,您仍然需要首先捕获C++异常。
extern "C" JNIEXPORT 
void JNICALL Java_MyClass_MyFunc(JNIEnv * env, jclass jc_, jstring param)
{
    try { //do not let C++ exceptions outside of this function

        //YOUR CODE BELOW THIS LINE.  HERES SOME RANDOM CODE
        if (param == NULL) //if something is wrong, throw a java exception
             throw NewJavaException(env, "java/lang/NullPointerException", "param");            
        do_stuff(param); //might throw java or C++ exceptions
        assert_no_exception(env); //throw a C++ exception if theres a java exception
        do_more_stuff(param); //might throw C++ exceptions
        //prefer Java exceptions where possible:
        if (condition1) throw NewJavaException(env, "java/lang/NullPointerException", "condition1");
        //but C++ exceptions should be fine too
        if (condition0) throw std::bad_alloc("BAD_ALLOC");
        //YOUR CODE ABOVE THIS LINE.  HERES SOME RANDOM CODE

    } catch(...) { //do not let C++ exceptions outside of this function
        swallow_cpp_exception_and_throw_java(env);
    } 

}