Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why aren't descendants of TInterfacedObject garbage collected?

i have a class based on TInterfacedObject. i add it to TTreeNode's Data property.

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

i create many instances of this object & had assumed that because they're reference counted, i shouldn't need to Free them. that'd be handy.

however, when checking this, i turned on ReportMemoryLeaksOnShutdown and found they're not being freed after all.

these objects are being created in a frame that's placed on the main form. in the main form's FormClose, i clear the tree nodes such that every object should be freed.

what's happening?

thank you for your help!

like image 737
X-Ray Avatar asked Nov 30 '22 20:11

X-Ray


2 Answers

TInterfacedObject itself is not reference counted, only interfaces are. You can implement interfaces using TInterfacedObject which basically saves you the effort of implementing the reference counting methods yourself. Unfortunately it still will not work in your case: The compiler does not know that you are assigning interfaces to the TTreeNode.Data property since it is not declared as an interface but as a pointer. So all kinds of weird things will happen:

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

As soon as you try to access your object through the .Data property, you will get an access violation.

So, don't bother with interfaces in this case, you could get it to work, but it will be much more effort than it is worth.

like image 121
dummzeuch Avatar answered Dec 05 '22 09:12

dummzeuch


You should declare the Field/Variable as Interface

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;

To access your fields, you should declare properties in IFacilityTreeItem Interface, with Getters and Setters.

like image 45
Cesar Romero Avatar answered Dec 05 '22 08:12

Cesar Romero