1

好的,所以我有一个使用 SWIG 向 Lua 公开的 C++ 类。该脚本创建对象,但管理器类也有一个指向该对象的指针,因此无论出于何种原因都可以在 C++(或其他脚本)中对其进行修改。

问题是当脚本完成对象被释放时,如何控制垃圾收集器收集的内容而无需实现 gc 元方法?

这是一个例子:

--Script that creates the object
someObject = Utils.Object("Obj name");

现在对象已经向管理器注册了自己,因此应用程序的其余部分(和其他脚本)可以访问它。

--Another script
obj = ObjManager:GetObject(0);

显然不是一个非常现实的例子,但希望它能说明我的问题。有没有办法在没有 C++ 中的 gc 元方法的情况下否决垃圾收集器?

只是为了澄清管理器是用 C++ 编写的,而 Utils 是包含公开类的模块名称。该对象还在其构造函数中将自己注册到管理器。

提前致谢。

4

2 回答 2

2

Lua 的 GC 只知道 Lua 中持有的引用,这是一个合理的实现约束。这意味着对象的生命周期在 Lua 的控制之下。如果通过执行一个脚本或函数创建的对象需要供以后的脚本或函数使用,则必须在 Lua 状态中保留对它的引用,以便 GC知道它仍在使用中。否则与垃圾无异,随时可能被丢弃。

这是 Lua 注册表的用途之一。C 端可以通过将任何 Lua 对象放在注册表中来轻松地保存对它的引用。键可以是 C 库已知的某个唯一值(static转换为轻量用户数据的变量的地址通常是一个不错的选择,因为它不会与任何其他库中的任何键发生冲突)。或者,函数调用luaL_ref(L, LUA_REGISTRYINDEX)会将该项放在注册表中堆栈的顶部,并返回一个唯一的整数键。这适用于存储脚本提供的回调函数,既保护函数免受 GC 影响,又允许将指向它的“指针”(整数键)存储在 C 结构中,以便可以检索和调用它之后。

请注意,它luaL_ref()可用于管理任何表中的引用,因此使用模块专用的表而不是全局注册表可能非常有意义。在这种情况下,表ObjManager本身可能是一个很好的候选者。

于 2009-05-07T21:46:50.903 回答
0

是的; 让 Utils.Object 将对象填充到私有表中。那么它永远不会被收集,但你可以玩游戏(代码未测试):

do
  local retained = { }  -- table forces objects to be retained
  local old_util_object = Util.Object
  Util.Object = function(...)
    local obj = old_util_object(...)
    retained[obj] = true
    return obj
  end
  Util.Free = function(obj)
    assert(retained[obj])
    retained[obj] = nil  -- now obj can be garbage-collected
  end
end

如果你想在 C++ 端解决同样的问题,让你的 C++ 代码分配一个私有表并将它放在 Lua 注册表中。然后你可以玩相同的插入/删除游戏,只使用 C API 而不是 Lua 源。假设您熟悉 Lua 的 C API,这很简单。如果您以前没有使用过 C API,那么现在是开始学习的最佳时机。

于 2009-05-07T21:31:11.300 回答