DMarlon Studio

Lección 8 · 8 de 20

Try/finally y liberar recursos · Pascal

Garantice que sus objetos se liberan aunque haya errores con try/finally en Object Pascal, el patrón que evita fugas de memoria.

Pascal · Try/finally y liberar recursos en DMarlon Studio: el código del ejemplo y su salida en la terminal

En Pascal los objetos se liberan a mano, y un error a mitad de camino podría saltarse el Free. El bloque `try ... finally` lo impide: lo que va tras finally se ejecuta siempre, tanto si el código de try termina bien como si lanza una excepción.

Import sigue el patrón clásico: crea la lista antes del try (si Create fallara, no habría nada que liberar) y la libera dentro de finally. Entre medias convierte cada texto con StrToFloat y lo añade a prices.

La primera llamada importa los tres precios y escribe el total. En la segunda, StrToFloat('n/a') lanza EConvertError tras importar 12.00. Fíjese en el orden de la salida: primero Freeing a list of 1, porque el finally se ejecuta mientras la excepción sale, y después Import failed, cuando la captura el try ... except del programa principal.

finally no captura nada: la excepción sigue su camino y por eso This line is skipped nunca aparece. Los dos bloques se complementan: `finally` limpia y `except` decide qué hacer con el error. En una aplicación de Lazarus, todo objeto temporal debería ir protegido así.

Código · main.pas

program main;uses SysUtils, Classes;procedure Import(const rows: array of String);var  prices: TStringList;  row: String;  total: Double;begin  prices := TStringList.Create;  try    total := 0;    for row in rows do    begin      total := total + StrToFloat(row);  // may raise EConvertError      prices.Add(row);    end;    WriteLn('Imported ', prices.Count, ' prices, total ', total:0:2);  finally    WriteLn('Freeing a list of ', prices.Count);    prices.Free;  // runs with or without an error  end;end;begin  Import(['9.95', '24.50', '3.20']);  try    Import(['12.00', 'n/a', '7.40']);    WriteLn('This line is skipped');  except    on E: Exception do WriteLn('Import failed: ', E.Message);  end;end.

Salida · fpc main.pas && ./main

Imported 3 prices, total 37.65
Freeing a list of 3
Freeing a list of 1
Import failed: "n/a" is an invalid float

Para recordar

  • Lo que hay en finally se ejecuta siempre.
  • Cree el objeto antes del try y libérelo en finally.
  • finally no detiene la excepción; solo limpia.
  • except decide qué hacer con el error; finally, qué liberar.
  • Así se evitan las fugas de memoria.

Ejercicio

Haga que Import guarde los precios válidos en un fichero con prices.SaveToFile('prices.txt') justo antes del finally, y compruebe que en la segunda llamada no llega a escribirse.