Pregunta

Sé que es por diseño que no puedes controlar lo que sucede cuando se destruye un objeto. También soy consciente de definir algún método de clase como finalizador.

Sin embargo, ¿es el lenguaje ruby ??para RAII de C ++ (los recursos se inicializan en el constructor, se cierran en el destructor)? ¿Cómo administran las personas los recursos utilizados dentro de los objetos, incluso cuando ocurren errores o excepciones?

El uso de garantizar funciona:

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

pero los usuarios de la clase tienen que recordar hacer todo el comenzar-rescate-asegurar-chacha cada vez que se debe llamar al método abierto.

Por ejemplo, tendré la siguiente clase:

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

El resource_handle no se cerrará si la excepción es causada por alguna otra clase y el script se cierra.

¿O el problema es que aún estoy haciendo esto también como en C ++?

¿Fue útil?

Solución

Para que los usuarios no " tengan que acordarse de hacer todo el comenzar-rescate-asegurar chacha " Combine rescue / asegúrese con rendimiento .

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

El código del cliente puede usarlo de la siguiente manera:

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

De hecho, así es como funciona File.open , lo que hace que la primera respuesta sea confusa en el mejor de los casos (bueno, fue para mis compañeros de trabajo).

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

Otros consejos

¿Qué tal si produce un recurso a un bloque? Ejemplo:

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

¿O el problema es que aún estoy haciendo esto también como en C ++?

Sí, es así porque en C ++ la desasignación de recursos ocurre implícitamente para todo en la pila. Pila desenrollada = recurso destruido = destructores llamados y desde allí se pueden liberar cosas. Dado que Ruby no tiene destructores, no hay " hacer eso cuando todo lo demás se hace con " lugar ya que la recogida de grabage puede retrasarse varios ciclos desde donde se encuentre. Tiene finalizadores, pero se llaman " en el limbo " (no todo está disponible para ellos) y se les llama en GC.

Por lo tanto, si tiene un identificador para algún recurso que es mejor liberar, debe liberarlo explícitamente. De hecho, el idioma correcto para manejar este tipo de situación es

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

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

En Ruby, utilizarías una declaración de asegúrese :

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

Esto será familiar para los usuarios de Python, Java o C #, ya que funciona como prueba / captura / finalmente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top