我目前在使用Luabind将Lua脚本化AI与C ++游戏连接时遇到问题。
我在循环内调用一个更新函数(每帧一次),这个函数从Luabind中注册的C ++函数中检索信息。
我的问题如下: 在可变的,不可预测的时间之后,Luabind中的断言失败导致中止。 错误总是发生在/usr/include/luabind/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)
答案 0 :(得分:3)
几天前我遇到了这个问题。在我的特定情况下,隐式创建的Lua表保存了在Lua中为每个对象重写的所有方法,这些表被垃圾收集,而底层的C ++对象则没有。因此,如果您尝试从C ++对象调用Lua成员函数,它将失败。
我的案例中的解决方案是只要C ++实例存活,就保持对lua表的引用。这就像将一个luabind :: object字段添加到C ++类然后在实例化类时设置它一样简单,并且在调用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_ptr
这样的引用,因为那时Lua部分得到了垃圾收集,以及shared_ptr,但是没有必然是指针引用的C ++实例。如果Lua正在管理整个实例,那么我看不到在C ++实例存在时如何删除Lua表。
答案 1 :(得分:1)
您似乎正在遭受对象的拆分所有权。当C ++类的包装器没有正确地包装虚拟方法时,通常会发生这种情况。
之前我遇到过这个问题但是在我仔细实现了包装后它就消失了。在我的图书馆,我不需要这里提到的解决方法。