我在我正在编写的应用程序中使用Lua的C API,并且我正在尝试确定我使用它的方式是否留下一些悬空指针(指针)。
假设我在C ++中有一个类似树的结构(实际上是类)
struct Leaf
{
DoSomeLeafStuff();
List<Leaf*> Children;
};
class Tree
{
public:
Tree() { };
virtual ~Tree()
{
/* iterate over Children and delete them */
};
void DoSomeTreeStuff();
Leaf getRoot() const { return _root; }
private:
Leaf* _root;
};
- 假设tree
已经创建并包含数据,我在Lua中使用它:
local root = tree:getRoot()
root:DoSomeLeafStuff()
现在我对Lua的getRoot()
的C实现看起来像:
int LuaStuff::TreeGetRoot(lua_State* L)
{
Tree* tree = *(Tree**)luaL_checkudata(L, 1, "MyStuff.Tree");
if (tree != NULL && tree->getRoot() != NULL)
{
int size = sizeof(Leaf**);
*((Leaf**)lua_newuserdata(L, size)) = tree->getRoot(); // allocate a pointer to a pointer
lua_setmetatable(L, "MyStuff.Leaf");
}
else
{
lua_pushnil(L);
}
return 1;
}
经过一些故障排除后,我能够让你的Tree和Leaf对象在你期望的时候释放出来。但到目前为止,我还没有找到一种令人信服的方式(至少对我而言)指针指针正在被清理干净。
我的问题是:我可以安全地假设由Lua的lua_newuserdata()分配的内存会被Lua的垃圾收集自动清理吗?
答案 0 :(得分:1)
我在Lua中包装自己的对象做了类似的事情。这就是我这样做的方式:
/*part of the functon, buffer_s is a structure holding pointer
to the real object and some other fields (like who actually created the object)
*/
buffer_s* b = (buffer_s*) lua_newuserdata(L, sizeof(buffer_s));
b->ptr = new buffer;
b->origin = FROM_LUA;
luaL_getmetatable(L, "buffer");
lua_setmetatable(L, -2);
现在,在启动库时我也做了类似的事情:
luaL_newmetatable(L, "buffer"); //create metatable
lua_pushcfunction(L,lua_buffer_delete); //push Lua compatible "destructor"
lua_setfield(L, -2, "__gc"); //place it in the metatable under __gc index
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_register(L, NULL, maps_buffer_m);
现在,Lua将在free()ing(通过GC)对象之前调用__gc元方法。您可以使用它来进行清理。
我这样做(功能的一部分):
if (b->origin == FROM_LUA)
{
delete b->ptr; //delete the object
b->origin = PTR_INVALID; //and mark it as invalid
b->ptr = NULL;
lua_newtable(L);
lua_setmetatable(L, 1); //set empty metatable, it's not buffer any more
return 0;
}
我希望它有所帮助:)
您可以考虑使用tolua ++或swig来自动执行绑定过程。它将节省大量时间,并可能以正确的方式处理对象的创建和删除。
答案 1 :(得分:0)
我建议你使用一些Lua Wrapper Class。我一直在我们的项目中使用它,它的工作非常好。它也使事情变得容易多了。 当你的Lua脚本结束时这个类,包装器会破坏你用来释放内存和所有用户数据的Lua状态。
我还认为,如果你做了类似的事情:
lua_close( mState );
您的userData也将被清除。