swigでラップされたc ++クラスのインスタンスをluaスタックにプッシュするにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/613282

  •  03-07-2019
  •  | 
  •  

質問

swigでラップされ、luaで登録されたクラスがあります。このクラスのインスタンスをluaスクリプトで作成できますが、すべて正常に動作します。

しかし、c ++コードで作成されたクラスのインスタンスにnew Xへの呼び出しがあり、la lua_state Lには呼び出したい関数があり、1つの引数、Xのインスタンスを受け入れるとします...その関数を呼び出す方法問題のコードの(一部)は次のとおりです(エラー処理は省略しました):

main.cpp

class GuiInst;
extern "C"
{
    int luaopen_engine (lua_State *L);
}

int main()
{
    GuiInst gui=new GuiInst;
    lua_State *L=luaL_newstate();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);
    lua_getglobal(L,"Init");
    //Somehow push gui onto lua stack...
    lua_pcall(L, 1, 0, 0));
    lua_close(L);
}

mainmenu.lua

function Init(gui)
    vregion=gui:CreateComponent("GuiRegionVertical");
end

現時点では、swigで生成されたcppファイルからいくつかの機能を公開し、それを呼び出すだけで機能することがわかっています。これにはいくつかの理由があります。複数のモジュールがあり、swigファイルのデフォルトのリンケージ仕様を変更する必要がある場合は動作しません(-DSWIGRUNTIME =を使用)。

main.cppに以下を追加します

extern "C"
{
    struct swig_module_info;
    struct swig_type_info;
    int luaopen_engine (lua_State *L);
    swig_module_info *SWIG_Lua_GetModule(lua_State* L);
    void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own);
    swig_type_info *SWIG_TypeQueryModule(swig_module_info *start,swig_module_info *end,const char *name);
}
//and then to push the value...
SWIG_Lua_NewPointerObj(L,gui,SWIG_TypeQueryModule(SWIG_Lua_GetModule(L),SWIG_Lua_GetModule(L),"GuiInst *"),0);

モジュールへのポインターを取得し、次に型へのポインターを取得し、swigs関数を呼び出して登録します。人間が読めるはずのないファイルを掘り下げなければならないのは不合理なことでした(したがって、ファイルの先頭に表示されます)。 (しかし、動作します!)

確かに、私がやろうとしていることを達成するためのより良い方法があります。

PSの高レベルPovで必要なのは、この間違いを回避するために、GuiInstのオブジェクトファクトリによって作成されたGuiコンポーネントを参照しないようにすることです。いくつかの非常に単純な(かつ非スウィッグ)Pythonモジュールとは別に、スクリプト言語に機能を公開するのは今回が初めてなので、アドバイスを受ける準備ができています。

アドバイスをありがとう!


RBerteigによるコメントへの応答

GuiInstのコンストラクターは、swigの実行時にluaのインスタンスの構築を防ぐために#privateに定義されているため、うまくいきません。私が防止しようとしていたのは、次のものでした(lua):

r=engine.GuiRegionVertical()
r:Add(engine.GuiButton())

" g = new GuiButton"を呼び出します次に、それをGuiRegionVertical(さまざまな理由でポインタを保存する必要があります)に登録し、「delete g」を呼び出すと、GuiRegionVerticalにはgへのダングリングポインタが残ります。

本当に発生する必要があるのは、GuiRegionVertical :: Add(GuiButton *)がGuiButton *の参照カウントをインクリメントし、その後、GuiRegionVerticalのデストラクタがすべてのコンテンツの参照カウントをデクリメントする必要があることです。 swigを使用してこれを行う方法。

それにより、プライベートコンストラクター、Guiオブジェクトファクトリー、および厄介な外部プログラムの必要がなくなります。

これについて間違っていますか?

ありがとう。

役に立ちましたか?

解決

単純で直接的な答えがありますが、それは最も効率的な答えではないかもしれません。 SWIGは、スクリプト言語側からオブジェクトを操作するためのラッパーを生成します。オブジェクトの場合、ラップされたコンストラクタも合成します。したがって、直接的な解決策は、LuaインタープリターがSWIGのコンストラクターを呼び出して新しいオブジェクトを作成することです。

ラップされた engine.GuiInst クラスの場合、ほぼ確実に次のようなことができます。

int main()
{
    lua_State *L=lua_open();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);

    luaL_dostring(L, "Init(engine.new_GuiInst())");

    lua_close(L);
}

スクリプトの起動のようなワンショットの場合、luaL_dostring()を介して文字列定数を実行することのペナルティはまったく悪くありません。ただし、イベントコールバックまたは内部ループでは回避するのが難しくなります。

ポインタを直接ラップされたオブジェクトに変換する方法があるべきだと思われますが、SWIGで生成されたラッパーのほんの一握りでそれを見つけているわけではありません。

編集:もちろん、LuaフラグメントをAPI呼び出しに分解して、スタック上のエンジンテーブルをグローバルに取得し、そこから new_GuiInst メンバーを抽出して呼び出すことができます、次にグローバルな Init を呼び出しますが、わずかな効率性は多少の明瞭さを犠牲にします。

ユーザーコードで偶然に構築されるべきではないオブジェクトを扱う場合、明確な質問が示すように、私の最初の衝動はSWIGにコンストラクター関数を生成させ、後で必要に応じてプライベート参照を保持し、それを削除することですテーブルから。 Cモジュールでさえ、(通常)メンバーに関数値が含まれる単なるテーブルです。 Cで実装されていても、余分な努力をしない限り読み取り専用にはなりません。

そのため、常に engine.new_GuiInst の値を取得し、レジストリに保存できます( luaL_ref() および擬似インデックス LUA_REGISTRYINDEX のLuaリファレンスマニュアルのセクション3.5を後で使用するために)。次に、ユーザーコードを実行する前に、 engine.new_GuiInst = nil と同等の操作を行います。私が最近遊んだCデータ型について、SWIGは各型に対して new_TYPE TYPE という名前の2つのコンストラクターを作成したことに注意してください。両方ともモジュールのテーブルに表示されていて、両方の名前を nil に設定する必要があります。 SWIGラップC ++クラスの経験がはるかに少ない場合、結果は異なる可能性があります...

SWIGによって返される engine テーブルのコンテンツ全体を確認および確認し、ユーザーが使用できるメソッドのみを含むプロキシオブジェクトを作成することをお勧めします。また、ユーザースクリプトに表示される環境を変更して、プロキシのみが使用可能であり、プロキシに engine という名前を付けます。 サンドボックスユーザースクリプトについてかなりの議論がありました。 ://www.lua.org/lua-l.html "rel =" nofollow noreferrer "> Luaリストおよび lua-users wiki

他のヒント

決して遅くなることはありません。この解決策は他の人にも役立ちます。

void handle_web_request(WebRequest *request, WebResponse *response)
{
  lua_getfield(rackam->lua_state, LUA_GLOBALSINDEX, "handle_web_request");
  SWIG_Lua_NewPointerObj(rackam->lua_state, request, SWIGTYPE_p_WebRequest, 0);
  SWIG_Lua_NewPointerObj(rackam->lua_state, response, SWIGTYPE_p_WebResponse, 0);
  lua_call(rackam->lua_state, 2, 0);
}

このコードは、.IGファイルの%{}%ブロック内にある必要があります。SWIGTYPE_p_WebRequestは

であるためです
#define SWIGTYPE_p_WebResponse swig_types[6]

およびswig_types [6]は

static swig_type_info *swig_types[12];

これは、swig_typesが定義元のC ++ファイルからのみアクセス可能であることを意味します。

この特定のスニペットは2つのラッパーポインターを送信しているため、C ++側からhandle_web_request(request、response)を呼び出すと、グローバルlua関数" handle_web_request"が実行されます。 SWIGマジックを適用して、2つのポインターを渡します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top