是否有Java的C ++等价物
try {
...
}
catch (Throwable t) {
...
}
我正在尝试调试调用本机Windows函数的Java / jni代码,并且虚拟机不断崩溃。本机代码在单元测试中看起来不错,并且仅在通过jni调用时似乎崩溃。通用的异常捕获机制将被证明非常有用。
是否有Java的C ++等价物
try {
...
}
catch (Throwable t) {
...
}
我正在尝试调试调用本机Windows函数的Java / jni代码,并且虚拟机不断崩溃。本机代码在单元测试中看起来不错,并且仅在通过jni调用时似乎崩溃。通用的异常捕获机制将被证明非常有用。
Answers:
try{
// ...
} catch (...) {
// ...
}
将捕获所有C ++异常,但应将其视为错误的设计。您可以使用c ++ 11的新current_exception机制,但是如果您无法使用c ++ 11(需要重写的旧版代码系统),则您没有命名的异常指针可用于获取消息或名称。您可能想为可以捕获的各种异常添加单独的catch子句,并且仅捕获底部的所有内容以记录意外的异常。例如:
try{
// ...
} catch (const std::exception& ex) {
// ...
} catch (const std::string& ex) {
// ...
} catch (...) {
// ...
}
有人应该补充说,在C ++代码中无法捕捉“崩溃”。那些不会抛出异常,但是会做任何他们喜欢的事情。当您看到由于空指针取消引用而导致程序崩溃时,它正在执行未定义的行为。没有std::null_pointer_exception
。尝试捕获异常将无济于事。
仅在某人正在读取此线程并认为他可以获取导致程序崩溃的原因的情况下。应该改用gdb之类的调试器。
try { .. } catch(...) { ... }
了使用信号/信号捕获的实现,我都不会称其为“捕获” :)如果在信号处理程序中,程序员相对很难知道崩溃在代码中的何处发生(我在说)关于以编程方式检测到的内容),与try / catch相比。
这是您可以在catch(...)
需要时使用GCC 从内部对异常类型进行逆向工程的方式(在从第三方库中捕获未知信息时可能很有用):
#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;
}
try {
// ...
} catch (...) {
// ...
}
注意...
里面的catch
是一个真实的省略号,即。三个点。
但是,由于C ++异常不一定是基Exception
类的子类,因此没有任何方法可以实际看到使用此构造时抛出的异常变量。
catch
在注释(// ...
)中将说明符与现有代码占位符区分开,这显然不是C ++语法。
(在C ++中)不可能以可移植的方式捕获所有异常。这是因为某些异常不是C ++上下文中的异常。这包括零错误除以除法和其他方法。发生这些错误时,可能会黑客入侵并因此而引发异常,但是这样做并不容易,而且肯定也不容易以便携式方式正确处理。
如果要捕获所有STL异常,可以执行
try { ... } catch( const std::exception &e) { ... }
这将允许您使用e.what()
,这将返回const char*
,可以告诉您有关异常本身的更多信息。这是您最想问的类似于Java构造的构造。
如果某人足够愚蠢以引发不继承自的异常,这将对您没有帮助std::exception
。
简而言之,使用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(...)
。
Foo
的析构函数?我认为这就是RAII的重点。但是,如果您需要指向a的指针Foo
而不是仅Foo
在堆栈上创建,则需要将指针包装在堆栈上声明的其他内容中。
可以这样写:
try
{
//.......
}
catch(...) // <<- catch all
{
//.......
}
但是这里有一个非常不明显的风险:您无法找到已在try
块中引发的错误的确切类型,因此catch
在确保无论异常类型是什么时,程序都必须持久化时,请使用这种类型的错误。按照catch
块中定义的方式。
您可以使用
catch(...)
但这很危险。约翰·罗宾斯(John Robbins)在他的《调试Windows》一书中讲述了一个战争故事,内容涉及一个由catch(...)命令掩盖的非常讨厌的错误。捕获特定的异常要好得多。捕获任何您认为您的try块可能会合理抛出的东西,但是如果确实发生某些意外情况,请让代码向上抛出一个异常。
让我在这里提一下:Java
try
{
...
}
catch (Exception e)
{
...
}
可能无法捕获所有异常!实际上,我以前曾经发生过这种事情,这很令人发指。异常源于Throwable。因此,从字面上看,要捕获所有内容,您就不想捕获异常。您想抓住Throwable。
我知道这听起来很挑剔,但是当您花了几天的时间试图找出“未捕获的异常”来自哪里时,该代码被try ... catch(Exception e)块所包围,它坚持您。
catch(Exception)
可能无法捕获Java中的所有异常,但是您会将其与C#混合在一起... Java = catch(Thowable)
,C#= catch(Exception)
。不要让他们感到困惑。
CoderMalfunctionError
(实际上是一个真正的Java Error
子类……虽然并不意味着听起来像什么。)
好吧,如果您想捕获所有异常以创建一个小型转储,例如...
有人在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(); //每一个
默认情况下,这会在当前目录(crashdump.dmp)中创建一个小型转储。
通用的异常捕获机制将被证明非常有用。
疑。您已经知道您的代码已损坏,因为它崩溃了。饮食异常可能掩盖了这一点,但这可能只会导致甚至更原始,更微妙的错误。
您真正想要的是调试器...
您是否可以从控制台窗口(从Java命令行启动)运行使用JNI的Java应用程序,以查看是否有关于JVM崩溃之前可能检测到的报告。直接作为Java窗口应用程序运行时,如果您从控制台窗口运行,则可能会丢失显示的消息。
其次,您是否可以对JNI DLL实现进行存根处理,以显示DLL中的方法是从JNI输入的,您是否正确返回等?
万一问题出在C ++代码中不正确使用JNI接口方法之一的情况下,您是否已验证一些简单的JNI示例可以编译并使用您的设置?我特别在考虑使用JNI接口方法将参数转换为本地C ++格式并将函数结果转换为Java类型。最好对它们进行存根,以确保数据转换有效,并且您不会在类似于COM的调用中进入JNI接口。
还有其他事情需要检查,但是很难在不了解您的本机Java方法是什么以及它们的JNI实现正在尝试做什么的情况下提出任何建议。目前尚不清楚从C ++代码级别捕获异常是否与您的问题有关。(您可以使用JNI接口将异常作为Java重新抛出,但是从您提供的内容中尚不清楚这是否会有所帮助。)
对于无法正确调试使用JNI的程序的实际问题(或在调试器下运行该错误不会出现):
在这种情况下,通常有助于在您的JNI调用周围添加Java包装器(即,所有本机方法都是私有的,而您的类中的公共方法则对其进行调用),这些包装器会进行一些基本的健全性检查(检查所有“对象”是否已释放并且“对象”是否已释放) (在释放后不使用)或同步(仅将所有方法从一个DLL同步到单个对象实例)。让Java包装器方法记录错误并引发异常。
这通常比尝试在一个程序库中调试大型并行Java程序更容易找到真正的错误(这出乎意料的是,该错误主要是在Java代码中不遵循被调用函数的语义,从而导致某些令人讨厌的double-frees或类似错误)。本机调试器...
如果您知道原因,则将代码保留在避免该问题的包装方法中。最好让包装器方法引发异常,而不是让JNI代码使VM崩溃。
意识到
try{
// ...
} catch (...) {
// ...
}
仅捕获语言级别的异常,其他低级别的异常/错误,例如Access Violation
,Segmentation Fault
不会被捕获。