デストラクタ
class TestDestructor @@refcount = 0 @@filelist = [] # TestDestructorが開いているファイルのリスト def initialize _set_finalizer(nil) @@refcount+=1 end def _set_finalizer( data) ObjectSpace.undefine_finalizer(self) ObjectSpace.define_finalizer( self, TestDestructor.cb(data)) @@filelist << data if data end def open( name) close p ["open", name] @name = name _set_finalizer(@name) end def close() return unless @name p ["close", @name] @@filelist.delete_at(@@filelist.index(@name)) @name = nil _set_finalizer(nil) end # 明示的な終了 def quit() close() # 開いているファイルがあるのでここで帰る return if @@filelist.size>0 # 終了処理 p ["quit"] end def TestDestructor.cb( data) lambda { # まだファイルを開いているなら閉じる p ["close_in_cb", data] if data @@refcount -= 1 p ["quit_in_cb"] if (@@refcount==0) # 誰もTestDestructorを参照していないので強制終了する } end end p "-- start --" d = TestDestructor.new() d.open( "test") d2 = TestDestructor.new() d.open( "test2") d2.open( "bar") d2.quit() p "-- end --"
これで,ファイルを開きっぱなしにしても勝手に閉じてくれる?
tempfile.rbを見ているうちに面倒になったので,適当に書き殴ってみた.
undefine_finalizerで検索してもあまり情報が出てこない.もっとましなやり方があるのだろうか.それとも自明すぎて誰も書いていないだけ?RAAのgonzuiで検索してもあまり出てこないところを見ると前者のような気がする.
この擬似コードの実際の使い道を考えると,a=TestDestructor.new(サーバに接続)→a.quit(接続オフ)→a.openとすると,接続が切れてるのでa.openに失敗する.quitの呼び出しを禁止するか,openで毎回接続を確認して再接続するか.