测试:
cpp
try_ctor();
try_call(
[]()
{
printf("1111111111111111111111\r\n");
int* p = NULL;
*p = 100;
throw 1;
// try_eeh();
},
[]()
{
printf("2222222222222222222222\r\n");
});
设置NULL指针P的值引发程式崩溃,可以被正确捕获(catch)处理,不支持 finally,可以自己改改,这是一个相对来说较为简洁的实现,该实现的代码可以在WIN、LINUX平台上编译通过且正常就绪运行。
try_call 保护代码快调用类似 lua 的 xpcall,try_ctor,注册所需的信号,try_eeh 是回到当前压入栈顶的结构化的异常处理器,vc++ 的seh 结构化处理也是这个处理,可以参考易语言seh结构化异常处理,写这个小哥是用汇编来写的,或者自己反调试看看seh展开的机器代码,思想上这个东西都差不多,但 try_catch 也有缺点,如果栈坏的很彻底就没法恢复了,比如C#.NET,单一时间内异常抛多了,catch 是捕获不了的,毕竟不是java 这类型的语言。
实现:
cpp
class __try_context__ final {
public:
jmp_buf __try_jmp_buf;
bool __try_jmp_flg;
public:
std::function<void()> __try_block;
std::function<void()> __try_catch;
public:
inline __try_context__()
: __try_jmp_flg(false) {
}
};
static thread_local std::list<std::shared_ptr<__try_context__>> __try_contexts__;
static thread_local std::shared_ptr<__try_context__> __try_eeh__;
static std::shared_ptr<__try_context__> try_seh_pop_context() noexcept {
auto tail = __try_contexts__.begin();
auto endl = __try_contexts__.end();
if (tail == endl) {
return NULL;
}
std::shared_ptr<__try_context__> context = std::move(*tail);
__try_contexts__.erase(tail);
return context;
}
static void try_seh_pop() noexcept {
std::shared_ptr<__try_context__> context = try_seh_pop_context();
context.reset();
}
static void try_seh_eeh_clear() noexcept {
__try_eeh__ = NULL;
}
static void try_seh_linux(__try_context__* context) noexcept {
int32_t signo = setjmp(context->__try_jmp_buf);
if (signo == 0) {
context->__try_jmp_flg = true;
context->__try_block();
try_seh_pop();
}
else {
context = __try_eeh__.get();
context->__try_catch();
}
try_seh_eeh_clear();
}
#ifdef _MSC_VER
static void try_seh_windows(__try_context__* context) {
__try {
try_seh_linux(context);
}
__except (sehCrashFilter(GetExceptionCode(), GetExceptionInformation())) { /* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH */
context->__try_catch();
try_seh_pop();
try_seh_eeh_clear();
}
}
#endif
void try_call(std::function<void()>&& __try_block, std::function<void()>&& __try_catch) {
if (NULL == __try_block) {
throw std::runtime_error("__try_block argument not allow is NULL.");
}
__try_context__* context = NULL;
if (NULL == __try_catch) {
throw std::runtime_error("__try_catch argument not allow is NULL.");
}
else
{
std::shared_ptr<__try_context__> try_context = std::make_shared<__try_context__>();
if (NULL == try_context) {
throw std::runtime_error("unable to make try context.");
}
else {
context = try_context.get();
}
try_context->__try_block = std::move(__try_block);
try_context->__try_catch = std::move(__try_catch);
__try_contexts__.emplace_back(try_context);
}
#ifdef _MSC_VER
try_seh_windows(context);
#else
try_seh_linux(context);
#endif
}
bool try_eeh() {
jmp_buf __try_jmp_buf;
for (;;) {
{
std::shared_ptr<__try_context__> context = try_seh_pop_context();
if (NULL == context) {
break;
}
if (!context->__try_jmp_flg) {
continue;
}
else {
__try_eeh__ = context;
}
memcpy(__try_jmp_buf, context->__try_jmp_buf, sizeof(__try_jmp_buf));
}
longjmp(__try_jmp_buf, 1);
return true;
}
return false;
}
void try_ctor() {
auto __try_eeh__ = [](int signo) noexcept -> void {
bool ok = try_eeh();
if (!ok) {
signal(signo, SIG_DFL);
raise(signo);
}
};
#ifdef __GNUC__
signal(SIGTRAP, __try_eeh__); // 调试陷阱
signal(SIGBUS, __try_eeh__); // 总线错误(常见于结构对齐问题)
signal(SIGQUIT, __try_eeh__); // CTRL+\退出终端
signal(SIGSTKFLT, __try_eeh__); // 进程堆栈崩坏
#endif
signal(SIGSEGV, __try_eeh__); // 段错误(试图访问无效地址)
signal(SIGFPE, __try_eeh__); // 致命的算术运算问题(常见于试图除以零或者FPU/IEEE-754浮点数问题)
signal(SIGABRT, __try_eeh__); // 程式被中止执行(常见于三方库或固有程式遭遇一般性错误执行abort()强行关闭主板程式)
signal(SIGILL, __try_eeh__); // 非法硬件指令(CPU/RING 0 ABORT)
}