web-dev-qa-db-ja.com

Luaのuserdataとlightuserdataとは何ですか?

  • Luaのuserdataとlightuserdataとは何ですか?
  • どこに必要ですか?

しばらく頭を包み込もうとしていますが、本当に理解できるチュートリアルや説明が見つからないようです。

なぜそれらが必要なのですか、なぜC関数をLuaメタテーブルに直接バインドできないのですか?

25
Lars

Userdataは、任意のサイズとコンテンツのガベージコレクションされた値です。 lua_newuserdata() を使用してC APIから作成します。これにより、スタックに作成およびプッシュされ、Cから適切と思われるように初期化するコンテンツへのポインターが提供されます。

これは、malloc()の呼び出しに非常に似ています。 malloc()との主な違いは、free()を呼び出す必要がないことです。代わりに、最後の参照を蒸発させるだけで、ガベージコレクターは最終的にストレージを再利用します。

これらは、Cから有用であるが、Luaから管理する必要があるデータを保持するのに最も役立ちます。これらは、CまたはC++オブジェクトをLuaにバインドできるようにする重要な機能である個々のメタテーブルをサポートします。ユーザーデータのコンテンツにアクセス、変更、使用するCで記述されたメソッドをメタテーブルに入力するだけで、Luaからアクセスできるオブジェクトが作成されます。この良い例は io library です。これは、C _FILE *_ポインターをユーザーデータに格納し、使い慣れたreadwriteおよび同様のメソッドを実装するバインディングを提供します。 ___gc_メタメソッドを実装することにより、ioライブラリは、そのfileオブジェクトの1つが、収集時に関連する_FILE *_を閉じるようにします。

軽いユーザーデータは、Luaで何かへのポインターを値として表す方法です。値であるポインタを使用して lua_pushlightuserdata() を呼び出すことで作成します。それらは、番号とほぼ同じ方法でLuaによって管理されます。これらは、Lua内で名前を渡すことができるようにCオブジェクトに名前を付ける必要があるが、オブジェクトの存続期間がLuaによって管理されていない場合に役立ちます。同じ値を持つ場合は数値が等しいのと同様に、同じポインターを保持している場合はライトユーザーデータは等しくなります。数値と同様に、スタック上にあるか変数に格納されている限り存在し、個別のメタテーブルがなく、ガベージコレクションも行われません。

50
RBerteig

さて、userdataはLua内から使用できるC側からのデータです。たとえば、io.inputとしてのファイルハンドルはuserdataです(print(type(io.input))を試してください)。 Lua C-APIをいじり始める場合(または、メタテーブルを設定できる空のユーザーデータを提供するnewproxy関数を使用する場合)、自分で必要になります(非表示の機能を参照 http:// lua-users.org/wiki/HiddenFeatures )(Lua-users wiki)。

良い紹介は次のとおりです: http://www.lua.org/pil/28.html

C関数については、Lua内から呼び出す関数としてC関数を登録するだけで済みますが、他のデータ型やC側のデータへのポインターなどは取得できません。

7
jpjacobs

userdataを使用できます。必要なデータがいくらかある場合はいつでも、luagcによって管理されます。たとえば、C++オブジェクトに使用できます。 userdataを使用したc ++オブジェクトの例:userdataに保存すると、luaによって管理されるため、C++では忘れることができます。したがって、luavariablesでそれを参照し、c ++オブジェクトのmemberfunctionを呼び出す関数に渡すことができます。 (もちろん、汎用関数オブジェクトをユーザーデータに配置するなど、一般化する方法があります。これをアップバリューとしてCクロージャにバインドし、そのCクロージャをC++オブジェクトのlua側を表すluaobjectに登録します。ユーザーデータも)。 lua gcにオブジェクトを管理させたくなく、luaからc ++オブジェクトを参照したい場合は、そのオブジェクトへのポインターをライトユーザーデータとして保存できます。

3
DaVinci

まず、userdataは完全なuserdataを意味します。 CharArrayを実装するための2つのソリューションを次に示します。下記を参照してください:

//full userdata 
extern "C" int newarray(lua_State* L)
{
     int n = luaL_checkint(L, 1);
     size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char);
     CharArray* a = (CharArray*)lua_newuserdata(L, nbytes);
     a->size = n;
     return 1;
}

//light userdata 
extern "C" int newlarray(lua_State* L)
{
    int n = luaL_checkint(L, 1);
    size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char);
    CharArray* a = (CharArray*)(new char(nbytes));

    lua_pushlightuserdata(L,a);
    a->size = n;

    return 1;
}

完全なユーザーデータは、事前定義された操作のない生のメモリ領域ですLuaから提供されます。したがって、ユーザーデータはガベージコレクターによって管理される必要があります。一方、light userdataは、Cポインターを表す値(つまり、void *値)にすぎません。ライトユーザーデータは、ガベージコレクターで管理する必要はありません(管理する必要はありません)。

2
chlin