前回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には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