Luabind中的断言失败

Assertion failure in Luabind

本文关键字:失败 断言 Luabind      更新时间:2023-10-16

我目前在使用Luabind将Lua脚本AI与C++游戏接口时遇到问题。

我在循环中调用一个更新函数(每帧一次),这个函数从Luabind中注册的C++函数中检索信息。

我的问题如下:在一个可变的、不可预测的时间之后,Luabind中出现断言失败,导致中止。在/usr/include/loabind/wrapper_base.hpp:124中下降时,错误总是出现Lua。

你知道怎样才能做到这一点吗?在我的测试中,C++和LUA中被调用的函数总是相同的。

有关问题的更多详细信息:

wrapper_base.hpp 中失败的断言周围的内容

typedef typename boost::mpl::if_<boost::is_void<R>, luabind::detail::proxy_member_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
, luabind::detail::proxy_member_caller<R, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
// Comments removed
lua_State* L = m_self.state();
m_self.get(L);
assert(!lua_isnil(L, -1));
detail::do_call_member_selection(L, name);
if (lua_isnil(L, -1))
  {
    lua_pop(L, 1);
    throw std::runtime_error("Attempt to call nonexistent function");
  }
// push the self reference as the first parameter
m_self.get(L);
// now the function and self objects
// are on the stack. These will both
// be popped by pcall
return proxy_type(L, args);

的确切错误

bomberman: /usr/include/luabind/wrapper_base.hpp:124: typename boost::mpl::if_<boost::is_void<T>, luabind::detail::proxy_member_void_caller<boost::tuples::tuple<boost::tuples::null_type,       boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type> >, luabind::detail::proxy_member_caller<R, boost::tuples::tuple<boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type> > >::type luabind::wrap_base::call(const char*, luabind::detail::type_<Derived>*) const [with R = void]:
Assertion `!(lua_type(L, (-1)) == 0)' failed.
Aborted (core dumped)

几天前我遇到了这个问题。在我的特定情况下,隐式创建的Lua表(其中包含Lua中为每个对象重写的所有方法)正在被垃圾收集,而底层C++对象则没有。因此,如果您试图从C++对象调用Lua成员函数,它将失败。

在我的案例中,解决方案是只要C++实例处于活动状态,就保持对lua表的引用处于活动状态。这很简单,只需向C++类添加一个luabind::object字段,然后在实例化类时设置它,当调用C++类的析构函数时,它将被销毁,所以在大多数情况下,您不必担心内存泄漏。我的代码现在看起来像这样:

class LuaC : public BaseC, public luabind::wrap_base {
    private:
        luabind::object _self; //retain a reference to the Lua part of this object so it doesn't get gc'd
    public:
        void setSelf(luabind::object nSelf) { _self=nSelf; }
};
//expose LuaC including the method setSelf
// ...

(BaseC是您正在包装的C++类)

然后从Lua中,每当实例化LuaC的实例时,调用setSelf并将self作为附加参数传递

c = LuaC()
c:setSelf(self)

如果没有一种方法可以简化这一点,并将其全部放在LuaC构造函数中,这样它就不容易出错(也就是说,你不必担心每次都调用setSelf),我会感到惊讶。但是LuaBind的文档相当肤浅,所以我找不到任何方法来做这件事。

此外,我认为发生这个问题的唯一方法是,如果您告诉Luabind只使用shared_ptrs之类的引用,因为这样Lua部分将被垃圾收集,同时还有shared_ptr,但不一定是指针引用的C++实例。如果Lua管理整个实例,那么我看不出当C++实例存在时,Lua表是如何被删除的。

您似乎正在遭受对象所有权分割的痛苦。当C++类的包装器没有正确地包装虚拟方法时,通常会发生这种情况。

我以前遇到过这个问题,但在我仔细实现包装器后,它就消失了。在我的库中,我不需要这里提到的变通方法。