zoukankan      html  css  js  c++  java
  • 给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
    ", lua_gettop(s));
    
        lua_rawgeti(s, LUA_REGISTRYINDEX, Myref);
        char* p = (char*)lua_touserdata(s, -1);
        printf("on_lua_close->p = %I64X
    ", p);
        delete p;
        lua_pop(s, 1);
        printf("on_lua_close->top = %d
    ", 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
    ", lua_gettop(s)); // 各种东西处理好之后,此时此处top应为0
    
        printf("p = %I64X, Myref = %d
    ", (__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
    ", 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);
    
        lua_autofree(s, n);
    
    
        lua_close(s);
        return 0;
    }
  • 相关阅读:
    Win10设置多时区时钟方法技巧
    Win10技巧:使用“照片”应用剪辑视频、添加特效
    kk录像机怎么剪辑视频 kk录像机视频剪辑教程
    360快剪辑怎么使用 360快剪辑软件使用方法介绍
    WPF HyperLink链接下划线隐藏
    ORACLE 如何产生一个随机数
    电脑的开始菜单点不了 用户帐户出现在桌面上
    无法加载DLL"***.dll":找不到指定的模块
    C#调用dll提示"试图加载格式不正确的程序"原因及解决方法
    C#中与C++中的 LPWSTR(wchar_t *) 对应的类型
  • 原文地址:https://www.cnblogs.com/babypapa/p/13364450.html
Copyright © 2011-2022 走看看