2012-02-08 8 views
6

En Delphi 5, actualmente he escrito un código que llama al Free en varias variables en un bloque finally, p. Ej.En Delphi 5, ¿puede Free alguna vez generar una excepción?

... 
finally 
    a.Free; 
    b.Free; 
    c.Free; 
end; 

Este código se supone que Free nunca puede aumentar, ya que si, por ejemplo, a.Free planteadas, la memoria para bc y sería filtrada. ¿Esta suposición está justificada?

+0

¿Por qué el voto a favor está fuera de interés? Es una pregunta clara, no hay ambigüedad y realmente quería saber la respuesta. * Se encoge de hombros * –

+0

Creo que aceptaste una respuesta aquí demasiado rápido. – NGLN

+0

@NGLN: De acuerdo en realidad (lo siento TOndrej), creo que la respuesta de David es mucho mejor. –

Respuesta

10

El método Free en sí mismo no genera explícitamente una excepción, pero llama al destructor virtual Destroy que ciertamente podría generar una excepción.

Así que si usted quiere estar seguro de que todos los objetos son destruidos, incluso si uno de los destructores lanza una excepción que terminan con un código como éste:

a := TMyObject.Create; 
try 
    b := TMyObject.Create; 
    try 
    ... 
    finally 
    b.Free; 
    end; 
finally 
    a.Free; 
end; 

Una vez dicho esto, que debería ser una principio de diseño de que no se generan excepciones en un destructor. Por lo tanto, desde mi punto de vista, es perfectamente razonable considerar que si se produce una excepción en el destructor, entonces su programa estará prácticamente contaminado. Los objetos que se escapan en ese punto no son algo de qué preocuparse. Si su destructor ha provocado una excepción, probablemente ya esté filtrando porque ese destructor no se ejecutó hasta su finalización.

Así que en mi opinión puede ser perfectamente razonable para agrupar algunas llamadas a Free y por supuesto a evitar anidada try/finally que es algo que vale la pena luchar.

Si desea sólo una try/finally a continuación, recordar que escribir el código como el siguiente:

a := nil; 
b := nil; 
try 
    a := TMyObject.Create; 
    b := TMyObject.Create; 
    ... 
finally 
    b.Free; 
    a.Free; 
end; 

En mi propia base de código que tengo algunos métodos auxiliares que hacen que este limpiador.A continuación, el código puede tener este aspecto:

InitialiseNil(a, b); 
try 
    a := TMyObject.Create; 
    b := TMyObject.Create; 
    ... 
finally 
    FreeAndNil(b, a); 
end; 

he dado mi FreeAndNil el mismo nombre que la función de SysUtils que a primera vista puede parecer extraño, pero es seguro y benigno para hacerlo. Naturalmente, estos ayudantes entran en acción cuando tienes más de dos objetos.

+0

+1 excelente respuesta, gracias. –

3

Depende de lo que ocurra en el destructor.

+0

Totalmente correcto, eliminé mi respuesta incorrecta. No tomé destructores en cuenta. Es por eso que los destructores no deberían lanzar excepciones. – jpfollenius

0

Por supuesto, el FREE puede emitir excepciones, por lo que sí, perderá memoria en su código si A.FREE emite una excepción, B.FREE y C.FREE no se invocarán.

La pregunta es, ¿desea manejar las excepciones o dejar que sucedan? Va a depender de para qué va a ser el código, otros desarrolladores lo van a usar (por ejemplo). Para evitar cualquier pérdida de memoria, debe anidar las secciones try..finally;

a:=tobject.create; 
try 
    b:=tobject.create; 
    try 
    c:=tobject.create; 

    ... 

    finally 
    c.free; 
    end; 
finally 
    b.free; 
end; 
a.free; 

Tipo de cosa. Es una cuestión de lo que realmente está haciendo tu código si también debes envolver el A.FREE en una sección try..finally también, aunque supongo que probablemente deberías hacerlo.

+3

Su 'a.free;' está fuera de cualquier 'try'..'finally', e intenta liberar' b' si 'b: = tobject.create;' genera una excepción (lo mismo con 'c'). – hvd

+1

Además, si 'c.free' genera una excepción, todavía tiene una fuga porque en realidad no ha liberado' c'. – hvd

+0

Es discutible que este sea un buen estilo de codificación de todos modos, pero dije que probablemente deberías probar ... por último también el a.free; Solo estaba demostrando cómo podrías hacerlo :-) –

1

si su a.free genera una excepción, a (dependiendo de cuánto ha liberado el destructor de los campos del objeto a), los objetos byc serán fugas porque la ejecución se interrumpirá. De todos modos, algo está mal en su destructor, si genera un error. por lo tanto, debe proteger el código con try..finally blocks, pero en mi humilde opinión debe verificar que los destructores no le den ningún error de circunstancia.

+2

La suposición de Stuart es "Gratis no puede presentar una excepción", y claramente puede hacerlo. –

+0

@FrankShearar. Gracias, he corregido la respuesta. – RBA

+1

No olvide, el objeto 'a' también se fugará si su destructor genera una excepción. – hvd

2

Podría haber 2 cosas que pueden causar SomeObj.Free a lanzar una excepción:

  1. excepción no controlada en el destructor de la SomeObj instancia de la clase o en la de sus antepasados.
  2. Referencia de clase no válida debido a la variable no inicializada SomeObj.

En su caso si a.Free lanza una excepción para cualquiera de las razones anteriores, no habría una pérdida de memoria para el objeto y bc y tal vez algunos de fugas en el interior de objeto a debido a excepción no controlada en el destructor.

Cuestiones relacionadas