给lua_close实现回调函数
先讲下为什么会需要lua_close回调吧。
我用C++给lua写过不少库,其中有一些,是C++依赖堆内存,并且是每一个lua对象使用一块单独的内存来使用的。
在之前,我一直都是魔改lua源代码,给lua_State结构添加新的成员来进行快速引用,并修改了lua_close的源代码,添加了回调函数,使lua在对象关闭时顺便把C++分配的内存也回收掉。
然而随着有相同需求的库不断增多,我随时需要调整lua的源代码的次数也在不断增加,这反而成了一种负担。
最重要的是,通过修改lua源码的方式,在使用lua_newthread来作为调用栈对象时,我需要自行区分这些C++对象的引用管理。
所以我一直在寻求一种能够在lua对象被关闭时,把我在C++为它申请的内存也释放掉的机制。
随着对lua的不断深入理解,我发现可以有这种方式。
原理:
给一个table设置__gc回调,然后将其直接放到注册表,就这么简单。
这个table会在vm对象被lua_close中进行回收,回收的同时回调我们指定的回调函数。
这代码,简直不要太简单,要不是搜索不到,我真的都不好意思发:
#include <iostream>
#include "lua.hpp"
#pragma comment(lib, "lua54.lib") int Myref = 0; static int on_lua_close(lua_State *s) { printf("on_lua_close->top = %d\n", lua_gettop(s)); lua_rawgeti(s, LUA_REGISTRYINDEX, Myref);
char* p = (char*)lua_touserdata(s, -1);
printf("on_lua_close->p = %I64X\n", p);
delete p;
lua_pop(s, 1);
printf("on_lua_close->top = %d\n", lua_gettop(s)); return 0;
} int main()
{
lua_State* s = luaL_newstate();
luaL_openlibs(s); // 创建第一个table
lua_newtable(s); // 创建第二个table用于构建元表
lua_newtable(s);
lua_pushcfunction(s, on_lua_close);//回调函数压栈
lua_setfield(s, -2, "__gc");//key命名为"__gc",设置完之后会自己弹出栈 // 将第2个table设置为第一个table的元表,设置完之后第二个表就弹出了,之后栈里就只剩第一个table
lua_setmetatable(s, -2); // 然后将第一个表放到注册表引用,引用完弹栈
luaL_ref(s, LUA_REGISTRYINDEX); // 下面是简单的测试
char* p = new char[10000];
lua_pushlightuserdata(s, p);
Myref = luaL_ref(s, LUA_REGISTRYINDEX);
printf("top=%d\n", lua_gettop(s)); // 各种东西处理好之后,此时此处top应为0 printf("p = %I64X, Myref = %d\n", (__int64)p, Myref); lua_close(s);
return 0;
}
那么,利用C++11的lambda函数,再结合C++的萃取机制,我们可以将任意需要释放的堆内存,完美捆绑到lua_close:
#include <iostream>
#include "lua.hpp"
#pragma comment(lib, "lua54.lib") template<typename _Ty>
void lua_autofree(lua_State* s, _Ty *p) {
lua_newtable(s); //指针入lua栈
lua_pushlightuserdata(s, p); //然后将其设置为数字key 1,lua的线性数组比string key速度要快一些,所以推荐这么干
lua_rawseti(s, -2, 1); lua_newtable(s);
lua_pushcfunction(s, [](lua_State* s)->int{
lua_rawgeti(s, 1, 1);
_Ty *ptr = (_Ty*)lua_touserdata(s, -1);
lua_pop(s, 1); //这个printf仅针对下面的int*的测试例子
printf("%I64X,%d\n", ptr, *ptr); delete ptr;
return 0;
});
lua_setfield(s, -2, "__gc");
lua_setmetatable(s, -2); luaL_ref(s, LUA_REGISTRYINDEX);
} int main()
{
lua_State* s = luaL_newstate();
luaL_openlibs(s); int *n = new int;
*n = 123;
printf("%I64X\n", n); lua_autofree(s, n); lua_close(s);
return 0;
}
给lua_close实现回调函数的更多相关文章
- 小兔JS教程(三)-- 彻底攻略JS回调函数
这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...
- 嵌入式&iOS:回调函数(C)与block(OC)传 参/函数 对比
C的回调函数: callBack.h 1).声明一个doSomeThingCount函数,参数为一个(无返回值,1个int参数的)函数. void DSTCount(void(*CallBack)(i ...
- 嵌入式&iOS:回调函数(C)与block(OC)回调对比
学了OC的block,再写C的回调函数有点别扭,对比下区别,回忆记录下. C的回调函数: callBack.h 1).定义一个回调函数的参数数量.类型. typedef void (*CallBack ...
- 理解 JavaScript 回调函数并使用
JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...
- 关于js的回调函数的一点看法
算了一下又有好几个月没写博客了,最近在忙公司android的项目,所以也就很少抽时间来写些东西了.刚闲下来,我就翻了翻之前看的东西.做了android之后更加感觉到手机端开发的重要性,现在做nativ ...
- JS学习:第二周——NO.1回调函数
[回调函数] 定义:把一个函数的定义阶段,作为参数,传给另一个函数: 回调函数调用次数,取决于条件: 回调函数可以传参: 回调函数可以给变this指向,默认是window: 回调函数没有返回值,for ...
- 【java回调】java两个类之间的回调函数传递
背景交代:熟悉用js开发的cordovaAPP:对java一窍不通的我,老师让做一个监测用户拍照事件的功能,无奈没有找到现成的库,无奈自己动手开发java插件~~0基础java GreenHand,祝 ...
- Java|今天起,别再扯订阅和回调函数
编程史上有两个令人匪夷所思的说辞,一个是订阅,一个是回调函数. 我想应该还有很多同学为“事件的订阅”和“回调函数”所困扰,因为事情本来就不应该按这个套路来解释. 多直白,所谓的“回调函数”你完全可以线 ...
- C++ 回调函数的定义与用法
一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...
随机推荐
- .NET 生态系统的蜕变之 .NET 6
.NET 6 是自.NET 4 框架以来生态系统看到的最大版本更新,虽然.NET Core 是2014年开始非常大的一项重大战略举措,但是.NET 6是真正的具有强大动力的非常重要的版本. 2021年 ...
- best-time-to-buy-and-sell-stock-ii leetcode C++
Say you have an array for which the i th element is the price of a given stock on day i. Design an a ...
- Luogu P3758 [TJOI2017]可乐 | 矩阵乘法
题目链接 让我们先来思考一个问题,在一张包含$n$个点的图上,如何求走两步后从任意一点$i$到任意一点$j$的方案数. 我们用$F_p(i,j)$来表示走$p$步后从$i$到$j$的方案数,如果存储原 ...
- Nginx多种安装方式
不指定参数配置的Nginx编译安装 ./configuremake make install wget下载或浏览器下载上传.解压进入目录[root@mcw1 nginx-1.10.2]# ls #查看 ...
- ShardedJedisPipeline 源码分析
一.什么是pipeline?什么是ShardedJedis? 由于pipeline和ShardedJedis的介绍和源码分析在网上已经有了,本文就不再赘述,直接给出链接: pipeline的介绍: h ...
- prometheus(4)之alertmanager报警插件
报警处理流程如下: 1. Prometheus Server监控目标主机上暴露的http接口(这里假设接口A),通过Promethes配置的'scrape_interval'定义的时间间隔,定期采集目 ...
- .NET Conf 2021 正在进行中,带你看一看微软带来了什么内容
今年最大的.NET活动正在进行, 可以通过Channel9 https://channel9.msdn.com/Events/dotnetConf/2021 看具体的Session .微软和社区一直在 ...
- tomcat9启动报错too low setting for -Xss
在tomcat下部署war包启动时报错,关键错误信息如下: Caused by: java.lang.IllegalStateException: Unable to complete the sca ...
- SeleniumLibrary 主要关键字 基于python3
关键字的解释 https://blog.csdn.net/ak739105231/article/details/88926995 click element 都是元素点击事件:不赘述 click l ...
- [hdu7042]二叉树
考虑最后这棵二叉树的结构,不难发现被移动的点在原树或新树中构成的都是若干棵完整的子树 (若$x$被移动,则$x$在原树或新树的子树中所有点都会被移动) 先在原树中考虑此问题,对于每一棵由被移动的点所构 ...