почему потомки мусора TInterfacedObject не собираются? - PullRequest
4 голосов
/ 27 января 2009

У меня есть класс, основанный на TInterfacedObject. я добавляю его в свойство данных TTreeNode.

TFacilityTreeItem=class(TInterfacedObject)
private
  m_guidItem:TGUID;
  m_SomeOtherNode:TTreeNode;
public
end;

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

однако, проверяя это, я включил ReportMemoryLeaksOnShutdown и обнаружил, что они не освобождаются в конце концов.

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

что происходит?

спасибо за вашу помощь!

Ответы [ 3 ]

16 голосов
/ 27 января 2009

Сам TInterfacedObject не учитывается, только интерфейсы. Вы можете реализовать интерфейсы, используя TInterfacedObject, что в основном экономит ваши усилия по реализации методов подсчета ссылок самостоятельно. К сожалению, это все равно не будет работать в вашем случае: компилятор не знает, что вы назначаете интерфейсы свойству TTreeNode.Data, поскольку оно не объявлено как интерфейс, а как указатель. Так что будут происходить разные странные вещи:

MyInt := TFacilityTreeItem.Create; // ref count = 1
// Node.Data := MyInt; // won't compile
Node.Data := pointer(MyInt); // no interface assignment, ref count stays 1
...
end; // ref count reaches 0, your object gets freed

Как только вы попытаетесь получить доступ к своему объекту через свойство .Data, вы получите нарушение доступа.

Итак, в этом случае не беспокойтесь об интерфейсах, вы можете заставить его работать, но это будет гораздо больше усилий, чем стоит.

3 голосов
/ 28 января 2009

Вы должны объявить поле / переменную как интерфейс

IFacilityTreeItem = IInterface
end;

TFacilityTreeItem=class(TInterfacedObject, IFacilityTreeItem)
private
  m_guidItem:TGUID;
  m_SomeOtherNode:TTreeNode;
end;

var
  Item: IFacilityTreeItem; // Variable as Interface
begin
  Item:= TFacilityTreeItem.Create;
...
end;

Чтобы получить доступ к вашим полям, вы должны объявить свойства в интерфейсе IFacilityTreeItem с методами получения и установки.

2 голосов
/ 17 февраля 2009

Как сказал dummzeuch , вы можете настроить это для работы с интерфейсами, но для этого потребуется еще немного кода, поскольку свойство Data у TTreeNode является указателем. Для всех, кто интересуется, как это сделать, эта ссылка имеет пример того, как это сделать для TListItem (это почти то же самое для TTreeNode). Вам также может быть полезно прочитать раздел об интерфейсах и последующий раздел о подсчете ссылок на этой странице.

...