根据我的理解,throw是一个灵长类似的jvm命令.调用它时,JVM"检查当前调用堆栈是否可以捕获它".如果它不能,那么java只是简单地弹出调用栈,就好像调用了一个返回一样.然后jvm"检查当前调用堆栈是否可以捕获它"等等递归.
我的问题:JVM在算法上如何知道调用堆栈中哪些地方可以捕获给定的异常?每个调用堆栈条目中是否存储了元数据,将异常映射到代码块?堆中是否有一个静态数据结构以某种方式跟踪它?因为某处必须有数据跟踪.
回答这个问题时,我注意到在处理异常时尝试移动"光标"时我得到了以下对话框:
无法将下一个语句设置为此位置.尝试解除callstack失败.
在以下情况下无法展开:
- 通过即时调试启动调试.
- 放松正在进行中
- 抛出了System.StackOverflowException或System.Threading.ThreadAbortException异常.
什么是放松?
我最近偶然发现了这个C++/Lua错误
int function_for_lua( lua_State* L )
{
std::string s("Trouble coming!");
/* ... */
return luaL_error(L,"something went wrong");
}
Run Code Online (Sandbox Code Playgroud)
错误是luaL_error使用longjmp,因此堆栈永远不会解开并且s永远不会被破坏,泄漏内存.还有一些Lua API无法解开堆栈.
一个显而易见的解决方案是在C++模式下编译Lua,但有例外.然而,我不能像Luabind那样需要标准的C ABI.
我目前的想法是编写我自己的函数,模仿Lua API的麻烦部分:
// just a heads up this is valid c++. It's called a function try/catch.
int function_for_lua( lua_State* L )
try
{
/* code that may throw Lua_error */
}
catch( Lua_error& e )
{
luaL_error(L,e.what());
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:function_for_lua堆栈是否正确解开.可能会出错吗?
试图构建我自己的非GNU跨平台C++环境,我遇到的事实是我并不真正理解堆栈展开的基础知识.我构建的环境如下:
libc++← libc++abi← libunwind(或一些其他退绕).
我发现libc++abi已经包含某种libunwind,但是在Linux上没有使用它.从我理解的评论中,它是特殊的libunwind:LLVM Stack Unwinder只支持Darwin和ARM但不支持x86_64 - 而且令人困惑.CPU体系结构如何影响堆栈展开过程?
我也知道关于堆栈取消器:
我期望得到完整涵盖这个主题的答案,而不仅仅是每个问题上的单独点.
我有一个简单的C++对象,我在函数F()的开头创建,以确保在F()的启动和返回时调用两个匹配的函数(OpDo,OpUndo),方法是使用对象的构造函数和析构函数.但是,如果在F()的主体内抛出异常,我不希望撤消操作.这可以干净利落吗?我读过有关std :: uncaught-exception的内容,但似乎并未建议使用它.
是否可以在#![no_std]模式下放松恐慌,例如使用定制的#[panic_handler]?
为了为我的同事和我的R脚本建立一个连贯的异常处理接口,我想使用以下tryCatch结构.
以下代码是我如何实现这些功能.但是,由于我不是R的专家,我想问一下这是否是一个好方法.特别:
Q1.可以不在内部tryCatch中指定错误处理程序并等待外部tryCatch处理该错误(参见上面的2b.和下面的代码)?
Q2.是否在处理程序中重新抛出相同的错误(参见上面/下面的2c)正确/认为良好的编码风格?
谢谢!
#outer tryCatch, see 1.
tryCatch({
#user code block
#2a. user specific tryCatch, object "vec" not defined
tryCatch(print(vec),error=function(e) {print("Non-fatal error. Script execution continued.");print(e);})
#2b. user specific tryCatch
tryCatch(vec*2)
#2c. user specific tryCatch
tryCatch(vec*parameter1, error=function(e) {print("Additional fatal error information. Script execution aborted.");stop(e);})
#end of user code block
},
#outer tryCatch error handler in order to handle fatal errors
error=function(e) {print("Fatal error");print(e);}
)
Run Code Online (Sandbox Code Playgroud) 未捕获的异常对主线程和另一个std :: thread的行为有所不同.
这是测试程序
#include <thread>
class XXX{
public:
XXX(){std::fprintf(stderr, "XXX ctor\n");}
~XXX(){std::fprintf(stderr, "XXX dtor\n");}
};
void mytest(int i)
{
XXX xtemp;
throw std::runtime_error("Hello, world!");
}
int main(int argc, char *argv[])
{
if(argc == 1) {
mytest(0);
}else{
std::thread th([&]{mytest(0);});
th.join();
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码(C++ 11),由GCC 5.4编译运行,没有args
XXX ctor
terminate called after throwing an instance of 'std::runtime_error'
what(): Hello, world!
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)
运行1 arg:
XXX ctor
XXX dtor
terminate called after throwing an instance of 'std::runtime_error'
what(): Hello, world!
Aborted …Run Code Online (Sandbox Code Playgroud) 在维基百科上的文件I/O的RAII的典型示例中,吞下关闭文件时发生的任何错误:
#include <iostream>
#include <string>
#include <fstream>
#include <stdexcept>
void write_to_file (const std::string & message) {
// try to open file
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("unable to open file");
// write message to file
file << message << std::endl;
// file will be closed when leaving scope (regardless of exception)
}
Run Code Online (Sandbox Code Playgroud)
似乎没有办法确定file自动关闭时是否发生错误; 显然一个只能调用file.rdstate()而file上的范围.
我可以file.close()手动调用然后检查错误,但是我必须在从示波器返回的每个地方都这样做,这违背了RAII的目的.
有些人评论说,在析构函数中只能发生文件系统损坏等不可恢复的错误,但我不相信这是正确的,因为析构函数AFAIK在关闭文件之前会刷新文件,并且在刷新时可能会发生可恢复的错误.
那么是否有一种常见的RAII方法来获取破坏期间发生的错误?我读到从析构函数中抛出异常是危险的,这听起来不像正确的方法.
我能想到的最简单的方法是注册一个回调函数,如果在破坏期间发生任何错误,析构函数将调用该函数.令人惊讶的是,似乎没有一个事件得到支持ios_base::register_callback.这似乎是一个重大的疏忽,除非我误解了一些事情.
但也许回调是在现代课程设计中被破坏时通知错误的最常见方式?
我假设在析构函数中调用任意函数也很危险,但是将调用包装在一个try/catch块中是完全安全的.