Pergunta

Eu sei que é por design que você não pode controlar o que acontece quando um objeto é destruído. Também estou ciente de definir algum método de classe como um finalizador.

No entanto é o idioma rubi para C ++ 's RAII (Recursos são inicializados no construtor, fechado em destructor)? Como as pessoas gerenciar recursos utilizados dentro de objetos, mesmo quando erros ou exceções acontecer?

Usando garantir funciona:

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

mas os usuários da classe tem que se lembrar de fazer o todo Begin-socorro-garantem chacha sempre que o abertos necessidades método a ser chamado.

Assim, por exemplo, eu vou ter a seguinte classe:

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

O resource_handle não será fechado se a exceção é causa por alguma outra classe e as saídas de script.

Ou o problema é mais do que eu ainda estou fazendo isso também C ++ -? Como

Foi útil?

Solução

Assim que os usuários não " tem que se lembrar de fazer o todo começam-socorro-garantir chacha " combinar rescue / ensure com 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

O código do cliente pode usá-lo da seguinte forma:

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

Na verdade, esta é a forma como File.open opera -. Fazer a primeira resposta confuso no melhor (bem foi a minha colegas de trabalho)

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

Outras dicas

Como cerca yielding um recurso a um bloco? Exemplo:

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

Ou o problema é mais do que eu ainda estou fazendo isso também C ++ -? Como

Sim, é uma vez que em C ++ desalocação de recursos acontece de forma implícita para tudo na pilha. Pilha desenrolado = recurso destruída = destruidores chamados e de lá coisas podem ser liberados. Desde o Ruby não tem destruidores não há "fazer isso quando tudo o resto é feito com" vigor desde coleção grabage pode ser adiada vários ciclos de onde você está. Você tem finalizadores, mas eles são chamados de "no limbo" (nem tudo está disponível para eles) e eles são chamados de GC.

Portanto, se você estiver segurando um identificador para algum recurso que melhor ser lançado você precisa liberá-lo explicitamente. Na verdade, a expressão correta de lidar com este tipo de situação é

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

http://www.rubycentral.com/pickaxe/tut_exceptions.html

Em Ruby, você usaria uma declaração ensure:

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

Esta será familiar aos usuários de Python, Java ou C #, em que ele funciona como try / catch / finally.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top