アーカイブ

2009 年 6 月 2 日 のアーカイブ

Luaの配列展開

2009 年 6 月 2 日

前回call_user_func関数の実装を行いました。

かなり便利になったのですが、すぐに1点の曇りが見つかりました。

そう、call_user_funcの場合、引数は直接指定しないといけないのです。

この手の関数を使う場面では、引数もあらかじめ配列に格納しておき、呼び出すことが多いのです。

例えば、以下のような関数が定義されていたとします。

function funcA(a,b,c)
        print(a,b,c)
end

これを普通に呼び出すのは簡単

funcA("a", "b", "c")

実行結果
a	b	c

しかし、とあるケースではこの引数を配列にしておきたいときがあります。

args = {"a", "b", "c"}

さて、funcAをどう呼び出すのか?

funcA(args)

実行結果
table: 0x806f168	nil	nil

当然ですが、第1引数にテーブルの参照が渡っているのです。

お察しのよろしい方は、タイトルでピンとくるでしょう。

そう、unpack関数があるのです。

funcA(unpack(args))

実行結果
a	b	c

あっという間に解決しました。

admin Lua

Luaのdestructor(デストラクタ)とGC

2009 年 6 月 2 日

LuaにはGCが付いていますので、使われなくなったメモリは回収されます。

強制的に呼び出すのは簡単で、回収したいところで

collectgarbage(“collect”)

とするだけです。

C++ではクラスインスタンスの解放時にデストラクタが呼ばれます。

自前のリソースの解放には便利です。

さっそく、Luaの自作クラスでやってみます。

何やらメタテーブルに__gcメソッドを書けばよろしいようで、簡単簡単。

function destruct()
        print("destructor called")
end

t = {}
setmetatable(t, {__gc = destruct})

t = nil
collectgarbage("collect")
print("end")

実行してみたものの、endしか表示されず、destruct関数が呼ばれない・・・

仕様を見てみると、ユーザデータ(テーブルではない)のメタテーブルに対して

__gcメソッドを定義しないといけない模様・・・

ユーザデータを作ってくれるnewproxy関数を発見!

この関数は非公開メソッドのようです。

この関数の引数がtrueなら、新しいメタテーブルを内包するユーザデータを作ります。

引数が既に作成してあるユーザデータなら、そのユーザデータに含まれるメタテーブルをコピーします。

先ほどのプログラムを次のように変更します。

function destruct()
        print("destructor called")
end

t = {_udata = newproxy(true) }
setmetatable(t._udata, {__gc = destruct})
t = nil
collectgarbage("collect")
print("end")

うまくいくだろうと思いきや、Luaが怒りました。

bad argument #1 to ‘setmetatable’ (table expected, got userdata)

つまり、setmetatable関数にはテーブルしか指定できないようです。

また調べると、getmetatable関数はユーザデータでも構わないとののこと。

もう一度プログラムを書き換えてみました。

function destruct()
        print("destructor called")
end

t = {_udata = newproxy(true) }
getmetatable(t._udata).__gc = destruct
t = nil
collectgarbage("collect")
print("end")

実行してみると・・・無事デストラクタが呼び出されました。

destructor called
end

admin Lua