luabind:从Lua访问一个已失效的C++对象会导致访问冲突。

luabind是否可以检查导出类(对象)的成员函数调用是否针对有效对象?

假设我有一个名为Actor的类,使用luabind将其暴露给lua。我正在使用一个actor对象作为参数从C++调用lua函数。现在,在函数完成之前,脚本编写器会将演员对象放在全局lua引用中,以便以后访问。

稍后,在C++端删除了actor对象,调用另一个函数尝试访问已失效的actor对象(它的任何方法)-显然,由于它已被删除,结果会导致崩溃(访问冲突)。

示例:

local myObjRef = nil

function doSomethingWithActor(actor)
 -- save, still valid object
 actor:Say("hello")
 myObjRef = actor
end

function calledAfterActorWasDeleted()
  --- will crash if the c++ object has been deleted meanwhile, works fine if it still exists
  myObjRef:Say("Crash...")
end

在这种情况下,NIL检查无效,这是否可以在luabind中检查?使用lua_pcall(....)执行函数,并且堆栈跟踪显示错误在luabind调用.hpp results = maybe_yield(L,lua_gettop(L) -参数,(Policies*)0)。

如果不行,是否有其他解决方案,以确保编写脚本的人无法创建这些问题?

点赞
用户734069
用户734069

现在,在函数结束之前,一个脚本会将演员对象放置在全局 Lua 引用中以供以后访问。

这就是你出现问题的原因所在。如果你希望 Lua 代码 拥有 这个对象(即保留该对象的存在),则需要使用 Luabind 机制告诉 Luabind 你想要这样做。否则,如果你将指针传递给某个 Lua 函数,Luabind 将假定该函数不会试图拥有它。

如果你希望所有权在 Lua 和 Luabind 之间 _共享_,则应将对象封装在 boost::shared_ptr 中,并使用 Luabind 的智能指针机制来实现这一点。

你也可以简单地更好地隔离脚本。如果你有一些操作特定演员的脚本,那么该脚本及其包含的任何函数应该随着对象一起被销毁(即失去对它的所有引用)。这需要在 C++ 方面有适当的编程纪律。它还需要使用 Lua 环境来适当地封装每个脚本的实例,以便它们不能通过全局变量偷偷传递任何东西。最后,你需要使 C++ 完全控制何时调用脚本和何时不调用。

否则,所有权就是你的脚本编写者需要知道并小心处理的事情。他们不能将 C++ 参数视为任何老的 Lua 值。


如果无法或不切实际地实行有纪律的编程实践,则必须不传递 Lua 实际的 C++ 对象。相反,你需要传递 Lua 一些代理对象,该对象是对原始对象的引用。boost::weak_ptr 是这样一个对象的良好示例(虽然你不会将它确切地传递给 Lua)。代理会将调用转发到实际对象。如果对象已被删除,则代理将检测到这一点并失败或不执行任何操作或其他操作。

2013-01-25 22:46:20
用户656250
用户656250

我用以下方法解决了我的问题:

当我要删除一个对象时,我遍历所有从C ++绑定到特定actor对象的lua函数(我将它们保存在列表中)。然后我检查每个upvalue(函数可访问的全局/局部变量) - 然后将userdata指针与我要删除的对象进行比较 - 如果它们匹配(并且它们的类是NIL upvalue),则它们匹配(并且它们的类是NIL upvalue)。可选地,我可以删除那个有问题的函数,因为它将不再起作用。

因此,下一次调用该函数时,我只会获得“尝试访问xxx nil值…”的软lua错误 - 不再存在访问冲突。

我知道人们会说“不要使用lua_getupvalue / lua_setupvalue - 它们只用于调试!” - 但实际上没有记录或口头副作用 - 在我的情况下,这是完全安全和有效的 - 并且没有剩余代理对象的问题我无法删除。

2013-01-31 11:05:12