清理内存的 C(++) 和 Lua

我正在使用Lua的C API编写一个应用程序,并且我正在尝试确定我使用它的方式是否会留下一些(指向指针的)悬空指针。

假设我有一个类似于树形结构的结构(实际上是类)在C++中

struct Leaf
{
  DoSomeLeafStuff();
  List<Leaf*> Children;
};

class Tree
{
public:
  Tree() { };
  virtual ~Tree()
  {
    /* 迭代 Children 并删除它们*/
  };

  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的垃圾回收自动清除?

点赞
用户1022729
用户1022729

我正在使用 Lua 包装自己的对象,这是我做的方式:

/*函数的一部分,buffer_s 是一个结构体,它包含指向真实对象及其它一些字段的指针(比如谁创建了这个对象)*/
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");  //创建元表
lua_pushcfunction(L,lua_buffer_delete); //推入 Lua 兼容的“析构函数”
lua_setfield(L, -2, "__gc");    //将其放置在元表的 __gc 索引下

lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");

luaL_register(L, NULL, maps_buffer_m);

现在 Lua 将在释放对象之前调用 __gc 元方法。您可以使用它进行清理。

我这样做(函数的一部分):

if (b->origin == FROM_LUA)
{

     delete b->ptr;   //删除对象
     b->origin = PTR_INVALID;  //将其标记为无效
     b->ptr = NULL;
     lua_newtable(L);
     lua_setmetatable(L, 1);        //设置空元表,这不再是 buffer
     return 0;
}

希望这有所帮助 :)

您可以考虑使用 tolua++ 或 swig 自动化绑定过程。它将节省大量时间,并且可能会正确处理对象的创建和删除。

2013-04-10 15:10:31
用户1027550
用户1027550

我建议您使用一些Lua Wrapper Class。我们在项目中一直在使用它,它的效果非常好。它还使事情变得更加容易。

使用这个类时,当 Lua 脚本结束时,包装器会销毁使用的 Lua 状态,释放您的内存和所有用户数据。

我还觉得如果您这样做:

lua_close( mState );

您的用户数据也将被清理。

2013-04-12 09:42:58