質問

オブジェクトが破壊されたときに何が起こるかを制御できないのは、設計によるものです。また、いくつかのクラスメソッドをファイナライザとして定義することも知っています。

しかし、C ++のRAIIのルビのイディオム(リソースはコンストラクターで初期化され、デストラクタで閉じられます)?エラーや例外が発生した場合でも、オブジェクト内で使用されるリソースをどのように管理しますか?

保証を使用すると動作します:

f = File.open("testfile")
begin
  # .. process
rescue
  # .. handle error
ensure
  f.close unless f.nil?
end

ただし、クラスのユーザーは、 openメソッドを呼び出す必要があるたびに、begin-rescue-ensure chacha全体を実行することを忘れないでください

たとえば、次のクラスがあります:

class SomeResource
 def initialize(connection_string)
   @resource_handle = ...some mojo here...
 end

 def do_something()
   begin
    @resource_handle.do_that()
    ...
   rescue
    ...
   ensure
 end

 def close
  @resource_handle.close
 end

end

例外が他のクラスによって引き起こされ、スクリプトが終了した場合、resource_handleは閉じられません。

それとも私がまだこれをしているのはC ++のような問題ですか?

役に立ちましたか?

解決

ユーザーが" begin-rescue-ensure chacha全体を忘れずに行う必要があるように" rescue / ensure yield を組み合わせます。

class SomeResource
  ...
  def SomeResource.use(*resource_args)
    # create resource
    resource = SomeResource.new(*resource_args) # pass args direct to constructor
    # export it
    yield resource
  rescue
    # known error processing
    ...
  ensure
    # close up when done even if unhandled exception thrown from block
    resource.close
  end
  ...
end

クライアントコードでは次のように使用できます。

SomeResource.use(connection_string) do | resource |
  resource.do_something
  ... # whatever else
end
# after this point resource has been .close()d

実際、これが File.open の動作です-最初の答えはせいぜい混乱させます(それは私の仕事仲間にとってでした)。

File.open("testfile") do |f|
  # .. process - may include throwing exceptions
end
# f is guaranteed closed after this point even if exceptions are 
# thrown during processing

他のヒント

ブロックへのリソースの yield はどうですか?例:

File.open("testfile") do |f|
  begin
    # .. process
  rescue
    # .. handle error
  end
end
  

それとも私がまだこれをしているのはC ++のような問題ですか?

はい、C ++ではスタック上のすべてのリソースの割り当てが暗黙的に解除されるためです。 Stack unwound =リソースが破棄され=デストラクタが呼び出され、そこから解放されます。 Rubyにはデストラクタがないため、「他のすべてが完了したら、それを行う」ことはできません。グラベージコレクションは現在地から数サイクル遅れる可能性があるためです。ファイナライザーはありますが、「リンボ」と呼ばれます。 (すべてが利用できるわけではありません)、GCで呼び出されます。

したがって、リリースする方がよいリソースへのハンドルを保持している場合は、明示的にリリースする必要があります。実際、この種の状況を処理する正しいイディオムは次のとおりです

def with_shmoo
  handle = allocate_shmoo
  yield(handle)
ensure
  handle.close
end
scroll top