给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++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...
随机推荐
- Linux过来人帮你理清学习思路
很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...
- 攻防世界 web2.robots
输入ip/robots.txt,显示出了flag目录,直接访问.
- HTML+CSS基础(HTML篇)
引言 在日常开发Android中,很多时候会遇到和WebView打交道,对CSS HTML JS不是很清楚的话是完不成一些功能的,本篇开始学习HTML,文章的主要内容是总结了慕课网中,HTML+CSS ...
- 链表中环的入口结点 牛客网 剑指Offer
链表中环的入口结点 牛客网 剑指Offer 题目描述 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null. # class ListNode: # def __init__(se ...
- 回文链表 牛客网 程序员面试金典 C++ Python
回文链表 牛客网 程序员面试金典 C++ Python 题目描述 请编写一个函数,检查链表是否为回文. 给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文. 测试样例 ...
- RocketMQ源码详解 | Broker篇 · 其二:文件系统
概述 在 Broker 的通用请求处理器将一个消息进行分发后,就来到了 Broker 的专门处理消息存储的业务处理器部分.本篇文章,我们将要探讨关于 RocketMQ 高效的原因之一:文件结构的良好设 ...
- flex步局 11.02
语法 justify-content: flex-start | flex-end | center | space-between | space-around flex-start:弹性盒子元素将 ...
- Java测试开发--MySql之C3P0连接池(八)
连接池C3P0! 连接池技术的目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能 ! 下面以案例演示下C3P0的操作流程. 1.测试准备: ①MySql数据库一枚②database名为myte ...
- 谷粒 | 18 | Hystrix熔断器
Spring Cloud调用接口过程 Spring Cloud 在接口调用上,大致会经过如下几个组件配合: Feign ----->Hystrix ->Ribbon ->Http C ...
- IDEA中三种注释方式的快捷键
三种注释方式 行注释.块注释.方法或类说明注释. 一.快捷键:Ctrl + / 使用Ctrl+ /, 添加行注释,再次使用,去掉行注释 二.演示代码 if (hallSites != null ...