3

現在、Luabindを使用してLuaスクリプトAIをC++ゲームとインターフェースする際に問題が発生しています。

ループ内で更新関数を呼び出し(フレームごとに1回)、この関数はLuabindに登録されているC++関数から情報を取得します。

私の問題は次のとおりです。変動する予測不可能な時間が経過した後、Luabindでアサーションが失敗し、アサーションが発生します。Lua内を下降している間、エラーは常に/usr/include/luabind/wrapper_base.hpp:124で発生します。

あなたはそれを何ができるかについて何か考えがありますか?私のテストでは、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)
4

2 に答える 2

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 ++クラスです)

Then from Lua, whenever you instantiate an instance of LuaC, call setSelf and pass self as an additional argument

c = LuaC()
c:setSelf(self)

I would be surprised if there isn't a way to simplify this and put it all inside the LuaC constructor so that it's less error-prone (ie so you don't have to worry about calling setSelf every time). But the documentation for LuaBind is rather shallow, so I couldn't find any way to do this.

Also, I believe the only way for this problem to occur is if you're telling Luabind to only use references like shared_ptrs, because then the Lua part get's garbage collected, along with the shared_ptr, but not necessarily the C++ instance referenced by the pointer. If Lua is managing the entire instance, then I don't see how the Lua table could get deleted while the C++ instance lives on.

于 2012-02-19T22:36:27.617 に答える
1

オブジェクトの所有権の分割に苦しんでいるようです。これは通常、C++クラスのラッパーが仮想メソッドを適切にラップアラウンドしない場合に発生します。

以前にこの問題が発生しましたが、ラッパーを慎重に実装すると問題は解決しました。私のライブラリでは、ここで説明した回避策は必要ありません。

于 2013-08-17T15:04:00.183 に答える