Reputation: 2383
I'm passing created object to a constructor of another object which need an Interface which that object implements.
ISomeInterface = interface
['{840D46BA-B9FB-4273-BF56-AD0BE40AA3F9}']
end;
TSomeObject = class(TInterfacedObject, ISomeinterface)
end;
TSomeObject2 = class
private
FSomeInterface: ISomeinterface;
public
constructor Create(SomeObject: ISomeInterface);
end;
var
Form1: TForm1; // main form
SomeObject: TSomeObject;
constructor TSomeObject2.Create(SomeObject: ISomeInterface);
begin
FSomeInterface := SomeObject;
end;
// main form creating
procedure TForm1.FormCreate(Sender: TObject);
var SomeObject2: TSomeObject2;
begin
SomeObject := TSomeObject.Create;
// SomeObject2 := TSomeObject2.Create(nil); // ok
SomeObject2 := TSomeObject2.Create(SomeObject); // not ok
try
// do some things
finally
SomeObject2.Free;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
SomeObject.Free; // if passed to a SomeObject2 Constructor - freeing it causing av
end;
After I close main form it gives me an AV and a memory leak - whole main form has leaked.
If I'm passing nil
to a TSomeObject
constructor everything is well. Is compilator freeing FSomeInterface
by reference counting and I'm shouldn't try to free SomeObject
in mainForm destructor
? How can I avoid it?
Upvotes: 2
Views: 595
Reputation: 47819
TSomeObject inherited from TInterfacedObject and thus is reference counted. Your instance of TSomeObject is not reference counted and should be removed or replaced by an interface variable.
If you need the instance of TSomeObject created in FormCreate, you should assign it to a variable of type ISomeInterface, so that the reference counting will work for that, too.
Another approach is to inherit from TInterfacedPersistant instead of TInterfacedObject to avoid the reference counting.
To explain what is happening in your code:
procedure TForm1.FormCreate(Sender: TObject);
var SomeObject2: TSomeObject2;
begin
{ Here you create the instance and assign it to a variable holding the instance.
After this line the reference count of the instance is 0 }
SomeObject := TSomeObject.Create;
// SomeObject2 := TSomeObject2.Create(nil); // ok
{ Using the instance as a parameter will increase the reference count to 1 }
SomeObject2 := TSomeObject2.Create(SomeObject); // not ok
try
// do some things
finally
{ Freeing SomeObject2 also destroys the interface reference FSomeInterface is
pointing to (which is SomeObject), decreasing the reference count to 0, which
in turn frees the instance of TSomeObject. }
SomeObject2.Free;
end;
{ Now, after SomeObject is freed, the variable points to invalid memory causing the
AV in FormDestroy. }
end;
Upvotes: 7