C++ 编译 Lua 从而使 Lua 利用 C++ 异常
Lua 源码文件 ldo.c 中有如下说明:
LUAI_THROW/LUAI_TRY define how Lua does exception handling. By default, Lua handles errors with exceptions when compiling as C++ code
搜索使用 C++ 编译 Lua 时,也有提到使用 C++ 异常: According to the Lua Wiki, if Lua 5.1 or later is compiled as C++, it will use C++ exceptions.
。
阅读这篇博客时,云大也提到:
看 ldo.c 前面的 LUAI_THROW LUAI_TRY 等宏就是做的这个事情。所以,如果你用 C++ 做宿主语言,就应该用 C++ 编译器编译 Lua 库。
并且在下面一段中的一句话给出了如果用 C++ 做宿主语言,应该用 C++ 编译 Lua 的原因:
Lua 在内部发生异常时,VM 会在 C 的 stack frame 上直接跳至之前设置的恢复点,然后 unwind lua vm 层次上的 lua stack 。lua stack (CallInfo 结构)在捕获异常后是正确的,但 C 的 stack frame 的处理未必如你的宿主程序所愿。也就是 RAII 机制很可能没有被触发。
上面这段话的意义在于在 Lua 中使用 C++ 异常,如果 Lua 抛出异常,此时走 C++ 异常机制,可确保对象被正确销毁,即析构函数被调用,也就保证了 RAII 机制。
举个例子,如下代码片段,在创建 C++ 对象 t
后发生了异常,此时使用 C++ 编译的 Lua 库,可保证 t
的析构函数会被调用。
static int test_func(lua_State *L) { Test t; luaL_error("there is an error here"); // 模拟 Lua C API 抛出异常 }
下面测试使用 C 和 C++ 编译的 Lua 库,来验证对象的析构函数是否会被调用。
- 编译 Lua 。
编译 C 版本 Lua 库:make linux
。库名为 liblua.a 。
编译 C++ 版本 Lua 库:make linux CC="g++"
。修改库名为 libluacc.a 。
- 编写 C++ 宿主程序,并编译。
#include <iostream> #include <string> #ifndef LUA_CLIB #include <lua/lua.h> #include <lua/lualib.h> #include <lua/lauxlib.h> #else #include <lua/lua.hpp> #endif using namespace std; class Test { public: Test() { cout << "Test ctor:" << this << endl; } ~Test() { cout << "Test dctor:" << this <<endl; } }; static int entry(lua_State *L) { cout << "enter entry" << endl; Test t; luaL_error(L, "there is an error"); cout << "exit entry" << endl; return 0; } int main() { lua_State *L = luaL_newstate(); lua_pushcfunction(L, entry); if (lua_pcall(L, 0, 0, 0)) { cout << "pcall error:" << lua_tostring(L, -1) << endl; } cout << "after function entry" << endl; lua_close(L); return 0; }
Makefile 如下:
tc: g++ -Wall -g -DLUA_CLIB -o tc main.cc ./liblua.a tcc: g++ -Wall -g -o tcc main.cc ./libluacc.a clean: rm -f tc rm -f tcc
- 运行 Lua 的 C 版本库对应的可执行文件
tc
和 Lua 的 C++ 版本库对应的可执行文件tcc
。
运行 tc
输出如下:
$ ./tc enter entry Test ctor:0x7ffdfd7b4677 pcall error:there is an error after function entry
运行 tcc
输出如下:
$ ./tcc enter entry Test ctor:0x7ffd25d86e47 Test dctor:0x7ffd25d86e47 pcall error:there is an error after function entry
可发现运行 tcc
时,对象 t
的析构函数执行了。
总之,要小心处理 Lua 中的异常,特别是在 C++ 中。在 C++ 中,即使 Lua 中的异常使用了 C++ 异常,要捕获 Lua 中抛出的异常,也只能通过 lua_pcall
或者 lua_resume
而不能使用 try catch
。详情阅读这里。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
sync.Pool实现原理
sync.Pool实现原理 对象的创建和销毁会消耗一定的系统资源(内存,gc等),过多的创建销毁对象会带来内存不稳定与更长的gc停顿,因为go的gc不存在分代,因而更加不擅长处理这种问题。因而go早早就推出Pool包用于缓解这种情况。Pool用于核心的功能就是Put和Get。当我们需要一个对象的时候通过Get获取一个,创建的对象也可以Put放进池子里,通过这种方式可以反复利用现有对象,这样gc就不用高频的促发内存gc了。 结构 type Pool struct { noCopy noCopy local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal localSize uintptr // size of the local array // New optionally specifies a function to generate // a value when Get would otherwise return nil. // It may not be changed c...
- 下一篇
hdfs Balancer剖析
balance过程就是从存储使用率超出集群平均使用率的datanode上将超出的block移动到低于集群平均使用率的datanode上,最终满足平衡标准。 over-utilized------>under-utilized over-utilized------>below-average above-average--->under-utilized 1. over-utilized :使用率超出阀值的datanode 2. above-average : 使用率超出平均值,但是低于阀值的datanode 3. below-average : 使用率低于平均值,但是高于阀值的datanode 4. under-utilized: 使用率低于阀值的datanode 平衡标准:参与balance的每个datanode的使用率 与 所有参与balance的全局的使用率 的差值 接近 给定的阀值threshold balance过程分多个迭代完成,每个迭代开始时balancer按照上面的规则将所有参与balance的datanode分类、配对,形成<source,...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Mario游戏-低调大师作品
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G