【问题标题】:Assertion failure in LuabindLuabind 中的断言失败
【发布时间】:2011-09-08 08:57:06
【问题描述】:

我目前在使用 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)

【问题讨论】:

  • 对答案感兴趣
  • 您能在您的系统上发布围绕 wrapper_base:124 的几行代码吗?还有完整的错误消息文本。
  • 你解决了吗?我遇到了完全相同的错误。

标签: c++ abort assertion luabind


【解决方案1】:

几天前我遇到了这个问题。在我的特殊情况下,隐式创建的 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 表。

【讨论】:

    【解决方案2】:

    您似乎正遭受对象所有权分割的困扰。这通常发生在 C++ 类的包装器未正确包装虚拟方法时。

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

    【讨论】:

    • 您能否详细介绍一下导致此类问题的包装器中的哪些陷阱?
    猜你喜欢
    • 1970-01-01
    • 2011-05-27
    • 2017-08-07
    • 2012-08-01
    • 2015-09-01
    • 2012-09-26
    相关资源
    最近更新 更多