Lua userdata 变量与 C++ 的交互
2016-8-23 10:56:38
收藏:0
阅读:112
评论:1
我有一个程序,用户可以使用 Lua 命令创建 Frame,例如:
frm=Frame.new()
上述命令会向用户显示一个窗口。在幕后,C++ 包装器如下所示:
Frame* Frame_new(lua_State* L)
{
int nargs=lua_gettop(L);
Frame* wb=0;
if(nargs==0){
//忽略
wb=mainfrm->GetFrame();
lua_pushlightuserdata(L,(void*)(wb));
int key=luaL_ref(L, LUA_REGISTRYINDEX);
wb->SetLuaRegistryKey(key);
}
return wb;
}
由于 Frame 被显示给用户,因此用户可以通过单击操作系统提供的关闭按钮来关闭 Frame。这会生成一个关闭事件,并且以下处理方式:
void Frm::OnClose(wxCloseEvent& evt)
{
//为了简洁而省略
int LuaRegistryKey=GetFrame()->GetLuaRegistryKey();
lua_rawgeti(glbLuaState,LUA_REGISTRYINDEX,LuaRegistryKey);//userdata
Frame* wb1=(Frame*)lua_touserdata(glbLuaState,-1); //userdata
lua_pop(glbLuaState,1); //
lua_getglobal(glbLuaState,"_G"); //table
lua_pushnil(glbLuaState); //table key
while (lua_next(glbLuaState,-2)) {//table key value
const char* name = lua_tostring(glbLuaState,-2);//table
if(lua_type(glbLuaState,-1)==LUA_TUSERDATA){
Frame* wb2=(Frame*)lua_touserdata(glbLuaState,-1);
if(wb2==m_Frame){ //此部分不起作用
lua_pushnumber(glbLuaState,0);
lua_setglobal(glbLuaState,name);
lua_pop(glbLuaState,1);
break;
}
}
lua_pop(glbLuaState,1); //table key
} //table
lua_pop(glbLuaState,1); //
if(m_Frame==wb1) {delete m_Frame; m_Frame=0; wb1=0;}
if(wb1) {delete wb1; wb1=0;}
luaL_unref(glbLuaState,LUA_REGISTRYINDEX,LuaRegistryKey );
}
现在的目标是,当用户关闭 Frame 时,由 frm=Frame.new() 创建的变量应该为 nil,以便用户无法调用其中的方法,比如 frm:size(),这会使程序崩溃。
在上述处理关闭事件的 C++ 代码中,wb1 和当前 Frame 具有相同的内存地址。现在,根据我的理解,我所需要做的就是在全局表中搜索 userdata 类型的 Frame,然后比较内存地址,以便知道我选择的是正确的 Frame,然后将其设置为 nil。
然而,Frame* wb2=(Frame*)lua_touserdata(glbLuaState,-1); 返回的地址与 wb1 完全不同,因此我无法知道我正在引用哪个类型为 Frame 的变量。
根据我的理解,wb2 具有不同的内存地址,可能出现 3 种情况:
frm是 full userdatafrm 在全局 lua 表中,因此具有不同的地址(尽管这对我来说没有意义,因为我在 C++ 中推送了 Frame 的地址)。
我完全错误地思考或者看不到简单的事情。
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

根据我的理解,我所需要做的就是在全局表中搜索
userdata类型的Frame并将其内存地址进行比较,以便我知道我正在选择正确的帧,然后将其设置为nil。你的理解是错误的。
首先,你没有将
userdata返回给Lua。你返回了轻量级userdata。这是不同的。轻量级userdata的lua_type是LUA_TLIGHTUSERDATA。其次,即使你修复了这个问题,你也没有遍历全局表内的表。所以即使出现这样一个简单的情况也会让你感到困惑:
global_var = {} global_var.frame = Frame.new()Lua代码应该能够将其数据存储在任何它希望的地方。如果它想在某个表中存储一些
userdata,你有什么权利阻止?第三,即使你递归地遍历过所有可全局访问的表(有防止无限循环的保护),也不能阻止这种情况发生:
local frm = Frame.new() function GlobalFunc(...) frm:Stuff(); end由于Lua有适当的词法作用域,
GlobalFunc会在内部存储对frm局部的引用。由于frm是一个local变量,您无法从全局变量中迭代访问它。一般来说,如果您将一个值传递给Lua,那么Lua现在拥有该值。它可以做任何它想做的事情,一般认为打破这个协议是不礼貌的。
虽然它并非不可能。处理它的方法是使用实际的
userdata而不是轻量级的userdata。每个常规的userdata是一个对象,一个完整的内存分配。在该分配内部,您将存储Frame指针。当该Frame需要被销毁时,您所要做的就是将userdata内的Frame指针设置为NULL。从概念上讲,在C ++中,它是这样的:
struct FramePtr { Frame *ptr; };Lua将传递一个
FramePtr的单个分配。因此,如果将该分配的FramePtr设置为NULL,则所有人都会看到它。不需要遍历全局表等等。当然,访问
FramePtr中的Frame需要额外的间接引用。但是,通过使用完整的userdata而不是轻量级userdata,您还可以将适当的元表附加到其中(轻量级userdata不会获得每个对象的元表;每个轻量级userdata共享相同的元表)。