7

私は、Lua 5.1、Win XP SP3 の cygwin + 最新パッチ x86、ブースト 1.48、gcc 4.3.4 を含む Ryan Pavlik のマスター ディストリビューションの luabind 0.9.1 を使用しています。Lua と boost は cygwin のコンパイル済みバージョンです。

静的バージョンと共有バージョンの両方で luabind のビルドに成功しました。

両方のバージョンで失敗する test_object_identity.cpp テストを除いて、両方のバージョンがすべてのテストに合格します。

問題を次の問題に突き止めました。テーブル内のエントリが非組み込みクラス (つまり、int、string などではない) に対して作成された場合、値を取得できません。

これを示すコードは次のとおりです。

#include "test.hpp"
#include <luabind/luabind.hpp>
#include <luabind/detail/debug.hpp>

using namespace luabind;

struct test_param
{
    int obj;
};

void test_main(lua_State* L)
{
    using namespace luabind;

    module(L)
    [
        class_<test_param>("test_param")
            .def_readwrite("obj", &test_param::obj)
    ];

    test_param temp_object;
    object tabc = newtable(L);
    tabc[1] = 10;
    tabc[temp_object] = 30;

    TEST_CHECK( tabc[1] == 10 );              // passes
    TEST_CHECK( tabc[temp_object] == 30 );    // FAILS!!!

}

tabc[1] は確かに 10 ですが、tabc[temp_object] は 30 ではありません! (実際にはゼロのようです)

ただし、 iterate を使用して tabc エントリを調べると、正しいキーと値のペアを持つ 2 つのエントリがあります。

何か案は?

ところで、次のように == 演算子をオーバーロードします。

#include <luabind/operator.hpp>

struct test_param
{
    int obj;
    bool operator==(test_param const& rhs) const
    {
        return obj == rhs.obj;
    }
};

module(L)
    [
        class_<test_param>("test_param")
            .def_readwrite("obj", &test_param::obj)
            .def(const_self == const_self)
    ];

結果は変わりません。

[] 演算子から settable() と gettable() に切り替えてみました。結果は同じです。キーのデフォルトの変換が呼び出されていることをデバッガーで確認できるので、そのどこかでエラーが発生していると思いますが、正確に何が問題なのかを理解することはできません。

次の簡単なテスト ケースが示すように、複合型の Luabind の変換には間違いなくバグがあります。

struct test_param : wrap_base 
{ 
    int obj; 
    bool operator==(test_param const& rhs) const 
    { return obj == rhs.obj ; } 
}; 

void test_main(lua_State* L) 
{ 
    using namespace luabind; 
    module(L) 
    [ 
        class_<test_param>("test_param") 
                .def(constructor<>()) 
                .def_readwrite("obj", &test_param::obj) 
                .def(const_self == const_self) 
    ]; 

    object tabc, zzk, zzv; 
    test_param tp, tp1; 
    tp.obj = 123456; 
    // create new table 
    tabc = newtable(L); 
    // set tabc[tp] = 5; 
    //         o     k   v 
    settable( tabc,  tp, 5); 
    // get access to entry through iterator() API 
    iterator zzi(tabc); 
    // get the key object 
    zzk = zzi.key(); 
    // read back the value through gettable() API 
    //              o     k 
    zzv = gettable(tabc, zzk);   
    // check the entry has the same value 
    // irrespective of access method 
    TEST_CHECK ( *zzi == 5 && 
                 object_cast<int>(zzv) == 5 ); 
    // convert key to its REAL type (test_param) 
    tp1 = object_cast<test_param>(zzk); 
    // check two keys are the same 
    TEST_CHECK( tp == tp1 ); 
    // read the value back from table using REAL key type 
    zzv = gettable(tabc, tp1); 
    // check the value 
    TEST_CHECK( object_cast<int>(zzv) == 5 ); 
    // the previous call FAILS with 
    // Terminated with exception: "unable to make cast" 
    // this is because gettable() doesn't return 
    // a TRUE value, but nil instead 
} 

うまくいけば、私より賢い誰かがこれを理解できるでしょう、Thx

複雑な値をキーとして使用するたびに Luabind が NEW DISTINCT オブジェクトを作成するという事実に問題を突き止めました (ただし、プリミティブまたはオブジェクトを使用する場合はそうではありません)。

これを示す小さなテスト ケースを次に示します。

struct test_param : wrap_base
{
    int obj;
    bool operator==(test_param const& rhs) const
    { return obj == rhs.obj ; }
};

void test_main(lua_State* L)
{
    using namespace luabind;

    module(L)
    [
        class_<test_param>("test_param")
            .def(constructor<>())
            .def_readwrite("obj", &test_param::obj)
            .def(const_self == const_self)
    ];

    object tabc, zzk, zzv;
    test_param tp;
    tp.obj = 123456;
    tabc = newtable(L);
    //         o     k   v
    settable( tabc,  tp, 5);
    iterator zzi(tabc), end;
    std::cerr << "value = " << *zzi << "\n";
    zzk = zzi.key();
    //         o     k    v
    settable( tabc,  tp,  6);
    settable( tabc,  zzk, 7);
    for (zzi = iterator(tabc); zzi != end; ++zzi)
    {
        std::cerr << "value = " << *zzi << "\n";
    }
}

tabc[tp] が最初に値 5 を持ち、キー オブジェクトを介してアクセスされると 7 で上書きされることに注意してください。ただし、tp を介して AGAIN にアクセスすると、新しいエントリが作成されます。これが、その後 gettable() が失敗する理由です。

Thx、デビッド

4

1 に答える 1

1

免責事項: 私は luabind の専門家ではありません。luabind の機能について何かを見逃している可能性は十分にあります。

まず、test_param を Lua キーに変換するとき、luabind は何をしているのでしょうか。デフォルトのポリシーはコピーです。luabind のドキュメントを引用するには:

これにより、パラメータのコピーが作成されます。これは、パラメータを値渡しするときのデフォルトの動作です。これは、C++ から Lua に渡す場合にのみ使用できることに注意してください。このポリシーでは、パラメーターの型にアクセス可能なコピー コンストラクターが必要です。

実際には、これが意味することは、Lua ガベージ コレクターが所有する新しいオブジェクト (「フル ユーザーデータ」と呼ばれる) を luabind が作成し、構造体をそこにコピーすることです。これは、c++ オブジェクトで何をするかが重要ではないため、非常に安全です。Lua オブジェクトはオーバーヘッドなしで残ります。これは、値による並べ替えのオブジェクトのバインドを行うのに適した方法です。

Lua にオブジェクトを渡すたびに luabind が新しいオブジェクトを作成するのはなぜですか? さて、他に何ができるでしょうか?渡されたオブジェクトのアドレスが同じかどうかは問題ではありません。これは、元の c++ オブジェクトが最初に Lua に渡された後で変更または破棄された可能性があるためです。(参照ではなく、値によって Lua にコピーされたことを思い出してください。) したがって、== のみを使用すると、luabind は、Lua に (おそらく弱い) 渡されたその型のすべてのオブジェクトのリストを維持し、比較する必要があります。それぞれに対してオブジェクトを作成して、一致するかどうかを確認します。luabind はこれを行いません (そうすべきだとも思いません)。

では、Lua 側を見てみましょう。luabind は 2 つの異なるオブジェクトを作成しますが、それらは同じですよね? 最初の問題は、特定の組み込み型を除いて、Lua は参照によってしかオブジェクトを保持できないことです。前に述べた「完全なユーザーデータ」のそれぞれは、実際にはポインターです。つまり、それらは同一ではありません。

しかし、__eq メタ操作を定義すると、それらは等しくなります。残念ながら、Lua 自体はこのケースをサポートしていません。ユーザーデータがテーブル キーとして使用される場合、常に ID によって比較されます。これは実際にはユーザーデータにとって特別なことではありません。テーブルにも当てはまります。(このケースを適切にサポートするために、Lua は __eq に加えてオブジェクトのハッシュコード操作をオーバーライドする必要があることに注意してください。Lua はハッシュコード操作のオーバーライドもサポートしていません。) Lua の作成者がなぜそうしなかったのかを代弁することはできません。これを許可します(そして以前に提案されました)が、そこにあります。

それで、オプションは何ですか?

  • 最も簡単な方法は、test_param をオブジェクトに 1 回 (明示的に) 変換し、そのオブジェクトを使用して 2 回ともテーブルのインデックスを作成することです。ただし、これでおもちゃの例は修正されますが、実際にはあまり役に立たないと思います。
  • もう 1 つのオプションは、そのような型をキーとして使用しないことです。実際、これは非常に良い提案だと思います。なぜなら、この種の軽量バインディングは非常に便利であり、他の唯一の選択肢はそれを破棄することだからです。
  • タイプでカスタム変換を定義できるようです。あなたの例では、タイプをテーブル インデックスとして適切に動作する Lua 数値に変換するのが合理的かもしれません。
  • 別の種類のバインディングを使用します。多少のオーバーヘッドは発生しますが、ID が必要な場合は、それに耐えなければなりません。luabind はラッパーをサポートしているようです。これは、ID を保持するために使用する必要がある場合があります。

    ラッパーを持つ登録済みクラスへのポインターまたは参照が Lua に渡されると、luabind はその動的型を照会します。動的タイプが wrap_base から継承されている場合、オブジェクト ID は保持されます。

于 2015-03-24T06:55:00.200 に答える