我正在与C一起在资源非常有限的系统中使用Lua。
我正在使用的库为它创建的对象创建一些引用(作为指针),这对于以后访问这些对象很有用。为了向Lua公开该库的功能,在创建此类对象时,该引用将返回到Lua脚本。
用户可以根据自己的喜好存储此引用,因为这使得以后的调用非常方便。
示例案例:
ref = MyLib.createObject("some", arguments)
local ref = MyLib.createObject("some", arguments)
table_of_refs[45] = MyLib.createObject("some", arguments)
-- etc...
不幸的是,这些引用可能在Lua脚本范围之外(在C中)被销毁。因此,这些引用可能无效。
目前,我的代码可以毫无问题地处理这些无效引用。所有这些指针都需要在库中实际使用之前经过验证,因此代码是安全的。
但是,从Lua用户的角度看,这似乎有点令人困惑,因为无法确定该引用是否仍然有效((这不是很重要,但我仍然想对其进行改进) 。
我想要的是以下内容。我想从C迭代Lua存储的所有lightuserdata。如果lightuserdatum不再有效,请将其设置为nil。这样,下次使用时变量将为有效或为零,从而为用户提供了更好的API。
有什么办法可以做到这一点?我可以从Lua知道的C 所有 lightuserdata迭代(无论它们存储在哪里,本地/全局/表等),并进行修改吗?
答案 0 :(得分:2)
无法从C访问局部lua变量。因此,即使您对某种类型的lua对象进行了迭代,也无法访问至少一个区域(局部变量)。
您可以遍历全局表中的所有内容,如Max在此处的答案所示:Loop through all Lua global variables in C++
如果要针对lua_islightuserdata进行测试,然后将lightuserdata的值与要删除的指针进行比较,那么您应该能够识别出想要的全局值。
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0)
{
if (lua_islightuserdata(L, -1))
{
//TODO: compare against the lightuserdata pointer value you are looking for
void* mypointer = lua_touserdata(state, -1);
name = lua_tostring(L,-2); // Get key(-2) name
//TODO: do whatever with the value; probably set to nil by name in the global table
}
lua_pop(L,1);
}
lua_pop(L,1);
但是,如果要在表中搜索它,则必须包括lua_istable的附加检查,然后以相同的方式递归遍历表的值。
...
else if (lua_istable(L, -1)
{
//TODO: iterate each value in the table searching for lightuserdata
// or tables with further levels of recursion
}
...
但是,我认为,在MyLib上提供一种称为“ isValid”的方法会更直接,该方法会在使用该值之前返回该值是否仍然有效。
local ref = MyLib.createObject("some", arguments)
...
local isvalid = MyLib.isValid(ref)
那么您就不受本地范围的限制。另外,假设您仍然会在lua代码中进行nil检查(以查看值是否从您的下面更改了),那么就代码而言,这基本上不会花费您什么。
答案 1 :(得分:0)
我认为您在概念上已经走错了路。
为什么可以从C中销毁创建的对象?是Lua脚本触发了创建,因此也应该是Lua脚本触发了破坏。
您可以设置标志来指示对象的无效状态,而不是破坏对象。您可能还需要实现一种回调机制,以便C库可以通知Lua脚本有关无效对象的信息。
如果要维护大量数据,并且希望尽快重用内存,那么Lua对象可能只是指向真实数据的指针的包装器。然后,您可以独立地删除数据,并将指针设置为NULL
,同时将其用作无效标志。
请注意,仅通过指针值本身检查指针有效性可能会严重失败:
SomeStruct* ptr = malloc(sizeof(SomeStruct));
// don't forget if(!ptr) error handling
SomeStruct* copy = ptr; // here C only, but might be stored in Lua!
SomeStruct* newPtr = malloc(sizeof(SomeStruct));
// by accident same address re-used as ptr once had!!!
if(isValid(copy))
{
// but the struct originally referenced died long ago...
}