1

我在我正在编写的应用程序中使用 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 的 C 实现getRoot()看起来像:

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 的垃圾收集自动清理吗?

4

2 回答 2

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() (通过 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 来自动化执行绑定的过程。它将节省大量时间,并且可能会以正确的方式处理对象的创建和删除。

于 2013-04-10T15:10:31.423 回答
0

我建议您使用一些Lua Wrapper Class。我一直在我们的项目中使用它,效果很好。它也使事情变得容易得多。当你的 Lua 脚本结束时,使用这个类,包装器会破坏你正在使用的 Lua 状态来释放你的内存,以及你所有的用户数据。

我还认为,如果您执行以下操作:

lua_close( mState );

您的 userData 也将被清理。

于 2013-04-12T09:42:58.687 回答