C(++)和Lua清理内存

时间:2013-04-10 11:35:13

标签: c++ memory-leaks lua

我在我正在编写的应用程序中使用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的垃圾收集自动清理吗?

2 个答案:

答案 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也将被清除。