给lua_close实现回调函数

先讲下为什么会需要lua_close回调吧。

我用C++给lua写过不少库,其中有一些,是C++依赖堆内存的,

然而lua并没有为我们提供回调函数的机制来解决我们在C++层次的内存释放问题。

所以,直观的做法是魔改lua源代码,给lua_close实现回调机制。

而不直观却是最优雅的方法,就是利用元表,注册表,来变相实现回调

原理:

给一个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;
}

猜你喜欢

转载自www.cnblogs.com/babypapa/p/13364450.html