Delphi - Как освободить объект, который принадлежит 2 (или более) спискам - PullRequest
1 голос
/ 29 января 2010

В проекте, над которым я работаю, есть случаи, когда несколько объектов TList содержат один и тот же объект item.

По сути, существует главный список, который содержит все объекты элементов, а затем меньшие списки, которые содержат только подмножество всех элементов. Элементы одинаковы, но не копия.

Где проблема возникает во время разрушения. Основной список освобождается, что освобождает все элементы. Основной список заботится об освобождении элементов путем переопределения «уведомлять», а подсписки переопределяют событие «Уведомлять», так что элемент не освобождается во второй раз - что в любом случае приведет к ошибке.

Однако при использовании FastMM4 в журнале утечки памяти перечисляются элементы как утечка памяти.

Так как же освободить объекты, принадлежащие двум или более спискам?

Кстати, это не мой код, я просто немного его поддерживаю. Я хотел бы избежать создания клона каждого объекта для включения в отдельные списки, если я могу, но эй, мужчина должен делать то, что должен делать мужчина: o)

Спасибо

Bourgui

EDIT

Неважно, я должен быть сумасшедшим. Теперь FastMM4 не помечает элементы как протекающие ... Только подсписки, которые на самом деле являются подклассом основного списка. Здесь должно быть что-то, чего мне не хватает. Я собираюсь провести больше тестов, чтобы получить более четкое представление о том, что происходит.

Спасибо за все ответы до сих пор.

Ответы [ 5 ]

4 голосов
/ 29 января 2010

Почему подсписки переопределяют события уведомления? TList не освобождает элементы, которые он содержит. Или вы говорите о списках TObjectLists? Если TList, вы уверены, что элементы действительно освобождены? Есть ли код, который это делает? Если нет, они не освобождаются, и fastmm прав: они протекают.

1 голос
/ 29 января 2010

@ dummzeuch правильно. Списки TList не освобождают содержащиеся элементы.

Если списки действительно TObjectLists, то TObjectList имеет концепцию владения, и по умолчанию объекты, добавленные в список, принадлежат списку и освобождаются при его уничтожении.

TObjectList имеет параметры OwnsObjects, которые имеют значение true, но есть перегруженный конструктор, который принимает параметр, который может быть установлен в значение False, чтобы содержащиеся объекты не принадлежали списку.

В вашем сценарии основной список будет иметь значение по умолчанию для параметра OwnsObjects, а вторичный список будет создан таким образом, чтобы они не владели содержащимися объектами.

1 голос
/ 29 января 2010

Прошло более 6 лет с тех пор, как я написал какой-либо Delphi, но в целом я думаю, что вы хотите сделать что-то вроде этого:

  • Как вы сказали, основной список освобождает все элементы, когда он сам освобождается;
  • Сублисты не пытаются освободить элементы, так как они освобождаются путем уничтожения основного списка. Скорее они просто удаляют элемент из своего списка, зная, что уничтожение обрабатывается в другом месте.

Это довольно лаконично, но я думаю, что это завершает общий шаблон, который вы хотите.

0 голосов
/ 29 января 2010

Это очень неэффективно, но, возможно, эффективность не является вашей первой целью, поэтому я должен сделать субкласс TList, создав для него определенный набор, который отслеживает все экземпляры TSharedList и, когда один элемент удалить в одном списке, выполнить поиск по всем остальным спискам и удалить элемент там же.

Примерно так (не безопасно для потоков):

unit SharedLists;

interface
uses Classes;

type
  TSharedList = class(TList)
  protected
    procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

var
  SharedListTracker: TList;
  RecursiveCallFlag: Boolean;

procedure TSharedList.Notify(Ptr: Pointer; Action: TListNotification);
var
  I: Integer;
begin
  if RecursiveCallFlag then
    Exit;
  RecursiveCallFlag := True;
  try
    if Action = lnDeleted then
      for I := 0 to SharedListTracker.Count - 1 do
        if (TSharedList(SharedListTracker[I]) <> Self) and (TSharedList(SharedListTracker[I]).IndexOf(Ptr) <> -1) then
          TSharedList(SharedListTracker[I].Remove(Ptr);
  finally
    RecursiveCallControl := False;
  end;
end;

constructor TSharedList.Create;
begin
  inherited Create;
  SharedListTracker.Add(Self);
end;

destructor TSharedList.Destroy;
begin
  SharedListTracker.Remove(Self);
  inherited;
end;

initialization
  SharedListTracker := TList.Create;
finalization
  SharedListTracker.Free;
end.

Я почти уверен, что он не компилируется (никогда не пытался), но он показывает мою идею.

0 голосов
/ 29 января 2010

Вы можете попробовать использовать механизм автоматического подсчета ссылок для интерфейсов в Delphi.Таким образом, объекты освобождаются, как только очищается последняя ссылка, и вам не нужно освобождать их явно.Для этого объекты, содержащиеся в списке, должны наследоваться от TInterfacedObject и реализовывать некоторый интерфейс.

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