Как автоматически освободить классы / объекты? - PullRequest
12 голосов
/ 06 января 2009

Какие существуют методы автоматического освобождения объектов в приложениях Delphi?

Ответы [ 8 ]

19 голосов
/ 06 января 2009

Используйте интерфейсы вместо объектов. Они считаются по ссылкам и автоматически освобождаются, когда счетчик ссылок достигает 0.

12 голосов
/ 07 января 2009

Я написал функцию GC (obj: TObject) (для сбора мусора), которая берет объект и освобождает его, когда выполнение покидает текущий метод. Это что-то вроде однострочной сокращенной функции для блока Try finally Free.

Вместо:

procedure Test;
var AQuery: TQuery;
begin
  AQuery := TQuery.Create(nil);
  try
    ...
  finally
    FreeAndNil(AQuery);
  end;
end;

У меня просто есть:

procedure Test;
var AQuery: TQuery;
begin
  AQuery := TQuery.Create(nil);
  GC(AQuery);
  ...
end;

Функция GC просто возвращает объект в форме интерфейса.

function GC(obj: TObject): IGarbo;
begin
  Result := TGarbo.Create(obj);
end;

Поскольку класс TGarbo происходит от TInterfacedObject, когда объект TGarbo выходит из области видимости, он автоматически освобождается. В деструкторе объекта TGarbo он также освобождает объект, который вы передали ему в своем конструкторе (объект, который вы передали в функции GC).

type
  IGarbo = interface
    ['{A6E17957-C233-4433-BCBD-3B53C0C2C596}']
    function Obj: TObject;
  end;

  TGarbo = class(TInterfacedObject, IGarbo)
  private
    FObj: TObject;
  public
    constructor Create(AObjectToGC: TObject);
    destructor Destroy; override;
    function Obj: TObject;
  end;

{ TGarbo }

constructor TGarbo.Create(AObjectToGC: TObject);
begin
  inherited Create;
  FObj := AObjectToGC;
end;

destructor TGarbo.Destroy;
begin
  if Assigned(FObj) then
    FreeAndNil(FObj);
  inherited;
end;

function TGarbo.Obj: TObject;
begin
  Result := FObj;
end;

Застряв в мире Delphi 7 и не ожидая обновления до версии Delphi со встроенной сборкой мусора в ближайшем будущем, я пристрастился к использованию этого краткого метода быстрого освобождения локальных временных объектов! :)

7 голосов
/ 06 января 2009

Вдоль линий интерфейсов, вы можете попробовать функцию Guard в блоке JclSysUtils, часть бесплатной библиотеки кодов джедаев . Он позволяет связать объект с отдельной интерфейсной ссылкой, поэтому, когда эта интерфейсная ссылка уничтожается, объект уничтожается вместе с ним. Это может быть полезно, когда у вас нет возможности изменить используемые вами классы, чтобы они поддерживали собственные интерфейсы.

var
  G: ISafeGuard;
  foo: TStrings;
begin
  // Guard returns TObject, so a type-cast is necessary
  foo := Guard(TStringList.Create, G) as TStrings;
  // Use the object as normal
  foo.Add('bar');
end; // foo gets freed automatically as G goes out of scope

Существуют перегрузки для объектов и GetMem -распределенных указателей. Существует также IMultiSafeGuard, который может обеспечить освобождение нескольких объектов.

Если у вас есть фабричная функция, возможно, вы создаете объект, устанавливаете некоторые его свойства и затем возвращаете его. Если при настройке свойств возникает исключение, вам нужно убедиться, что вы освободили объект, поскольку не можете его вернуть. Один из способов сделать это так:

function Slurp(const source: TFileName): TStrings;
begin
  Result := TStringList.Create;
  try
    Result.LoadFromFile(source);
  except
    Result.Free;
    raise;
  end;
end;

С Guard это станет так:

function Slurp(const source: TFileName): TStrings;
var
  G: ISafeGuard;
begin
  Result := Guard(TStringList.Create, G) as TStrings;
  Result.LoadFromFile(source);
  G.ReleaseItem;
end;

Метод ReleaseItem отменяет владение ISafeGuard объектом. Если перед тем, как это произойдет, возникнет исключение, то, когда стек раскручивается и интерфейс освобождается, охранник освобождает объект.

6 голосов
/ 06 января 2009

Я должен сказать, что мне не нравится «прятать» Свободный от объекта. Гораздо лучше иметь традиционный код:

MyObject := TObject.Create;
try
  // do stuff
finally
  FreeAndNil(MyObject);
end;

Никоим образом это не может пойти не так, работать, как ожидалось, и люди распознают шаблон.

5 голосов
/ 06 января 2009

Используйте владение объектами компонентов, которые предоставляет VCL. Пока вы создаете объекты с ненулевым владельцем, вам не нужно явно освобождать их. Смотрите также мой ответ на этот вопрос.

2 голосов
/ 09 января 2009

Вот API для Boehm Garbage Collector DLL для Delphi. Delphi API написан Барри Келли , который сейчас работает для CodeGear и пишет компилятор.

1 голос
/ 06 января 2009

Умные указатели работают очень хорошо, если у вас Delphi 2009.

0 голосов
/ 06 января 2009

Если вы используете Delphi для .Net / Delphi Prism, вы получаете сборщик мусора, который берет на себя все освобождения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...