I want to build a class TParent
containing several child objects by using aggregation. Some of the objects are independant, while some can be also dependant on the other children. All the children objects have to have a reference to the parent. I also want to use the interfaces where possible.
For this purpose I am using TInterfacedObject
for the TParent
and TAggregatedObject
for the children. As both the child and the parent know about each other, I am using weak references in order to avoid the circuar dependency. In fact this behaviour is already defined in TAggregatedObject
. Everything works fine when I am using only the independant child objects (TIndependantChild
).
The problem arises when the child object depends on the other children too, see the constructor of TDependantChild
. I store the reference to the another child object in fChild variable, which is marked with the [weak]
attibute, introduced in Delphi 10 Berlin. FastMM4 reports memory leaks on shutdown:
Also access violation leading to System.TMonitor.Destroy
raises, but this happens only when FastMM4 is in the uses and ReportMemoryLeaksOnShutDown is True.
program Project1;
{$APPTYPE CONSOLE}
uses
FastMM4,
System.SysUtils;
type
IParent = interface
['{B11AF925-C62A-4998-855B-268937EF30FB}']
end;
IChild = interface
['{15C19A4E-3FF2-4639-8957-F28F0F44F8B4}']
end;
TIndependantChild = class(TAggregatedObject, IChild)
end;
TDependantChild = class(TAggregatedObject, IChild)
private
[weak] fChild: IChild;
public
constructor Create(const Controller: IInterface; const AChild: IChild); reintroduce;
end;
TParent = class(TInterfacedObject, IParent)
private
fIndependantChild: TIndependantChild;
fDependantChild: TDependantChild;
public
constructor Create;
destructor Destroy; override;
end;
{ TParent }
constructor TParent.Create;
begin
fIndependantChild := TIndependantChild.Create(Self);
fDependantChild := TDependantChild.Create(Self, fIndependantChild);
end;
destructor TParent.Destroy;
begin
fDependantChild.Free;
fIndependantChild.Free;
inherited;
end;
{ TDependantChild }
constructor TDependantChild.Create(const Controller: IInterface; const AChild: IChild);
begin
inherited Create(Controller);
fChild := AChild;
end;
var
Owner: IParent;
begin
ReportMemoryLeaksOnShutDown := True;
Owner := TParent.Create;
Owner := nil;
end.
I found, that using [unsafe] instead of [weak] solves the problem, but according to the delphi help
It ([unsafe]) should be only used outside the System unit in very rare situations.
Therefore, I am not convinced, that I should use [unsafe]
here, especially when I don't understand what happens.
So, what are the reassons of the memory leaks in this situation and how to overcome them?