【问题标题】:Delete all of my Lua userdata in C++在 C++ 中删除我所有的 Lua 用户数据
【发布时间】:2025-12-21 05:45:11
【问题描述】:

我想知道是否可以访问所有用户数据“表”(是否称为用户数据表?)然后从 Lua 中删除它们,因为这是我的问题:

a = Object(5, 5)
a:Delete()
a:SetPosition(3,3)

正如您首先看到的,我创建了一个对象并保存了一个指向名为 Object 的 c++ 类的指针,该类是在我的地图类中使用“new”分配的。然后我删除对象,这意味着我删除了为地图类中的指针分配的内存。最后我调用 SetPosition,如果内存仍然是为 c++ Object 类分配的,那么一切都会很有趣。但是如果它被删除(在这种情况下,因为我们在 SetPosition(...) 调用之前调用了 Delete())我的程序将崩溃。所以我想知道的是:

是否可以通过调用 Delete 将 lua 中的变量 'a' 设置为 nil ?我知道如果 Delete 返回 nil,我可以执行类似 'a = a:Delete()' 的操作,但如果我忘记执行 'a =' 部分,它会失败。另外我想知道是否可以删除用户数据并在我调用 SetPositon() 时检查它是否不存在,如果不存在,我将返回。

另外,基础代码来自:http://lua-users.org/wiki/SimpleCppBinding

【问题讨论】:

    标签: c++ pointers lua lua-userdata


    【解决方案1】:

    首先,让我回答你的问题:

    是否可以通过调用 Delete 将 lua 中的变量 'a' 设置为零?

    没有。没有办法按照你说的去做。这是有原因的:你正在尝试做的是糟糕的代码。

    Lua 是一个垃圾收集系统。 Lua 不应该删除 对象。如果 Lua 得到一个指向某个外部对象的指针,那么要么你的代码拥有它,要么 Lua 拥有它。

    如果你的代码拥有它,Lua 不应该删除它。 Lua 可以使用它一段时间。但这取决于您的 Lua 代码是否准确且仅在该时间段内使用它。一旦它的生命周期结束,Lua 就不应该再和它说话了。

    这与在 C 和 C++ 中处理指向对象的指针没有什么不同。如果您的函数被传递给一个裸指针(即:不是智能指针),您的代码需要知道它可以合理地期望与该对象对话多长时间。可以储存吗?它可以将指向该对象的指针存储多长时间?那个物体什么时候会死,谁负责摧毁它?

    如果您将一个对象传递给 Lua,使得 Lua 现在拥有该对象,那么 Lua 也不应该显式删除它。 Lua 是一个垃圾收集系统;您应该将__gc 元方法附加到您的类型,以便Lua 的垃圾收集器在收集用户数据时调用您的代码。这样就可以调用析构函数、释放内存等。

    当你给 Lua 一些现在属于 Lua 的东西时,它应该看起来像一个普通的 Lua 对象。您不会为在 Lua 中创建的表和字符串调用 Delete 方法;你让垃圾收集器完成它的工作。作为编写 C++ 到 Lua 接口的人,你的工作是确保你提供给 Lua 的对象的行为方式符合 Lua 的要求。

    如果你需要做重要的资源管理,你希望 Lua 尽快释放资源(例如文件句柄等),那么你需要在里面存储一个指向你的 C++ 对象的指针 的非轻量级用户数据。那是你 NULL 出来的指针。该对象上的所有接口函数都会检查指针以查看它是否为 NULL,然后什么也不做或引发错误。

    Lua 的文件句柄(由io.open 返回)就是一个很好的例子。如果你尝试在它们上调用函数,Lua 会抛出 Lua 错误。

    【讨论】:

    • 谢谢。但情况就是这样:当我创建我的对象时,它应该立即在屏幕上绘制,当脚本结束时,我不希望通过垃圾收集器删除该对象。我希望对象是“活着的”,直到我告诉它通过另一个 lua 脚本被删除。似乎使用垃圾收集器并删除对象只会导致对象立即被删除。我正在开发的是一款游戏,您可以在其中编写 npc 事件脚本并随时随地创建和删除 npc,而不会导致任何游戏崩溃。
    • 您阅读了所有帖子吗?特别是“如果您需要进行重要的资源管理......”段落?话虽如此,我不能说我同意您的 API 基于对象的存在/不存在。当事件结束时,您可以删除lua_State(这会导致收集所有垃圾)。让垃圾堆积到那时。用户可以有一个隐藏实体的功能(这样它就不会被绘制),但如果他们愿意,他们可以稍后取消隐藏。
    • 是的,我考虑过隐藏 NPC 并将这些 NPC 的指针移动到某种称为隐藏/删除的 NPC 的 std::vector 并在当前地图结束时删除它们?只是想知道在同一张地图上玩一个小时后会发生什么“/ Maby,你总共产生了 50.000 个 NPC。此外,我的游戏脚本将仅用作触发脚本,这意味着当我走在触发区域时,脚本将运行并且会发生一些事情(一个 npc 可能会产生)脚本可能只运行一秒钟,可能更少。然后我可以在没有脚本运行时清理“隐藏”的 npc?
    【解决方案2】:

    Delete 方法中,将接收到的对象的元表设置为nil,如果稍后调用该对象上的方法,则会收到错误消息。

    【讨论】:

    • 哦,请告诉我更多!我应该使用哪个功能?
    • 喜欢这个? luaL_getmetatable(L, "nil"); lua_setmetatable(L, -2);
    • 如果对象在栈顶,当你输入a:Delete()时它会在栈顶,然后执行`lua_pushnil(L); lua_setmetatable(L,1);`.请参阅我在tecgraf.puc-rio.br/~lhf/ftp/lua 的库以了解此技术的实际应用。
    • 好吧,这有点像。调用 delete 后出现错误并调用另一个函数,如 SetPosition(): 'Attempt to index global 'a' (a userdata value)。好的,在这样的情况下,是否有可能以任何方式执行以下操作:'if a then a:SetPosition(5,7) end'?
    • 我说你会得到一个错误。错误消息与预期一致。它只是告诉你a 不再理解它曾经使用的方法。而且,不,没有办法将它设置为 nil。
    【解决方案3】:

    我宁愿建议改用SWIGLuaBind,他们已经为你解决了这些陷阱。

    【讨论】:

    • 我不会说他们会处理这些事情。两者都没有提供删除方法(它们正确使用 GC)。他们提供的是一种控制所有权的方法。您仍然必须正确使用这些工具并实际管理对象的所有权。
    • @NicolBolas 同意。我想,足够的所有权控制是这里最简单的解决方案,因为正如您已经指出的那样,单独取消 userdata 无论如何都不会产生什么影响。这些工具只允许专注于它,而不是发明智能指针的包装器。
    最近更新 更多