luabind:从lua访问无效的c ++对象会导致访问冲突

时间:2013-01-25 22:16:08

标签: c++ lua luabind

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

假设我有一个名为Actor的类,使用luabind暴露给lua。我使用actor对象作为参数从C ++调用lua函数。在函数完成之前,脚本编写会将actor对象放在全局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检查在这里没有帮助,这是可以在luabinds网站上检查的东西吗?函数使用lua_pcall(....)执行,stacktrace显示luabinds的错误call.hpp results = maybe_yield(L,lua_gettop(L) - arguments,(Policies *)0);

如果没有,是否有另一种解决方案如何确保编写脚本的人无法创建这些问题?

2 个答案:

答案 0 :(得分:2)

  

在函数完成之前,脚本编写会将actor对象放在全局lua引用中,以便以后访问。

这就是问题的来源。如果你想让Lua代码拥有对象(也就是说,保留这个对象的存在),那么你需要使用Luabind技术告诉Luabind你想要这样做。否则,如果您将指针传递给某个Lua函数,Luabind将假定该函数不会尝试获取它的所有权。

如果您希望Lua和Luabind之间的所有权共享,那么您应该将对象包装在boost::shared_ptr中,并使用Luabind的智能指针机制来执行此操作。

您还可以更好地隔离脚本。如果你有一些操作在特定actor上的脚本,那么该脚本及其包含的任何函数都应该与对象一起销毁(即:丢失对它的所有引用)。这需要C ++方面的正确编码规则。它还需要您使用Lua环境来正确封装脚本的每个实例,这样它们就不会通过全局变量来解决问题。最后,您需要让C ++完全控制何时调用脚本以及何时不调用脚本。

否则,所有权是您的脚本编写者必须要知道的并且要小心。他们不能像任何旧的Lua值那样处理C ++参数。


如果练习训练有素的编程练习对你来说是不可能或不实际的,那么你只需要将Lua传递给实际的C ++对象。相反,你需要传递Lua一些代理对象,这是对原始的引用。 boost :: weak_ptr是这样一个对象的一个​​很好的例子(虽然你不会将它完全传递给Lua)。代理会将调用转发给实际对象。如果对象已被删除,代理将检测到此情况并失败或无所事事或其他任何事情。

答案 1 :(得分:0)

我通过以下方式解决了我的问题:

当即将删除一个对象时,我遍历C ++中的所有lua函数(我将它们放在一个列表中,它们每个都绑定到特定的actor对象)。然后我检查每个upvalue(可访问函数的全局/本地变量) - 然后我将userdata指针与我要删除的对象进行比较 - 如果它们匹配(和它们的类)并且NIL是upvalue。或者,我可以删除那个有问题的功能,因为它无论如何都不会好起来。

所以下一次调用该函数时,我只是得到一个软的lua错误“试图访问xxx一个零值...” - 没有更多的访问冲突。

我知道人们会说“不要使用lua_getupvalue / lua_setupvalue - 它们只用于调试!” - 但实际上没有记录或说出的副作用 - 在我的情况下它非常安全并且运行良好 - 也没有遗留代理对象我无法删除的问题。