3

C++ コードといくつかの Lua スクリプトで使用するクラスがあります。クラスの関連部分は次のようになります。

typedef boost::shared_ptr<Thing> ThingPtr; // convenient

class Thing
{
public:
    Thing() { /* do some stuff */ }
    ~virtual Thing() { }

    ThingPtr createThing()
    {
        ThingPtr thing(new Thing);

        // initialization can't be done in constructor
        thing->doSomeInit();

        return thing;
    }     

// other stuff....

};

このクラスを Lua で公開します (バインディングや「派手な」ものは使用しません)。factory 関数を追加する前は、 Thingを作成する Lua 関数は次のようになりました。

int MyLua::newThing(lua_State* L)
{
    int size = sizeof(Thing);

    // allocate a new Thing object in place
    new ((Thing*)lua_newuserdata(L, size)) Thing();

    luaL_setmetatable(L, "MyStuff.thing");

    return 1;
}

ファクトリ関数を追加したら、次のようにしました。

int MyLua::newThing(lua_State* L)
{
    int size = sizeof(Thing);

    // allocate a new Thing object in place
    Thing* thing = new ((Thing*)lua_newuserdata(L, size)) Thing();
    thing->doSomeInit();

    luaL_setmetatable(L, "MyStuff.thing");

    return 1;
}

これは問題ないように見えましたが、C++ コードの他の場所でファクトリ関数の使用を強制するためにThingのコンストラクタをプライベートにしたいという点を除いては問題ありません。だから、今私は次のようなものを持っています:

int MyLua::newThing(lua_State* L)
{
    int size = sizeof(Thing);
    ThingPtr thing = Thing::createThing();

    void* space = lua_newuserdata(L, size);
    memcpy(space, client.get(), size);

    luaL_setmetatable(L, "MyStuff.thing");

    return 1;
}

私の質問は次のとおりです。これを行うためのより良い方法はありますか? memcpyの呼び出しは不快に感じます。

4

2 に答える 2

1

C++ オブジェクトの所有権を Lua に譲渡することはできません。

元のコードには欠陥があります。これは、Things のデストラクタを決して呼び出さないためです。Lua は によって割り当てられたメモリをガベージ コレクションしますlua_newuserdataが、オブジェクトのデストラクタを呼び出しません (単純に、C ライブラリである Lua はデストラクタの概念を認識していないためです)。

そのため、C++ 側でオブジェクトの有効期間を管理し、未加工の (所有していない) ポインターのみを Lua に渡してユーザーデータとして公開する別の構造が必要になります。

于 2013-10-02T10:45:04.643 に答える
1

それはあなたを不快にするはずです。memcpy自明にコピー可能な型 ( はそのような型ではありません) に対してのみ許可されますThingnew (lua_newuserdata(L, size)) Thing()Luaはreallocデフォルトで新しいメモリを要求するために使用され、これによりメモリが移動される可能性があるため、それが許可されているかどうかさえわかりません(つまり、とにかくそうなるrealloc可能性があります)。memcpy

解決策、IMOは、あなたを動的に割り当てThing(あなたのファクトリはそうしているようですが、スマートポインターを使用します)、オブジェクトをクリーンアップするメタメソッドをcreateThing使用して、オブジェクトへのCポインターをユーザーデータに保存します。__gcスマート ポインターの場合、これはより複雑になりますが、スマート ポインターのコピーをヒープに格納し、スマート ポインターへの C ポインターをユーザー データに格納してから、メタメソッドでスマート ポインターを解放する必要があります__gc

于 2013-10-02T10:32:53.923 に答える