我将创建的对象传递给另一个对象的构造函数,该对象需要该对象实现的接口。
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;
关闭主窗体后,它会给我一个AV和内存泄漏 - 整个主窗体已泄露。
如果我将nil
传递给TSomeObject
构造函数,一切都很顺利。编译器是否通过引用计数释放FSomeInterface
并且我不应该尝试在mainForm SomeObject
中释放destructor
?我怎么能避免它?
答案 0 :(得分:7)
TSomeObject继承自TInterfacedObject,因此被引用计数。您的TSomeObject实例未被引用计数,应该被接口变量删除或替换。
如果需要在FormCreate中创建的TSomeObject实例,则应将其分配给ISomeInterface类型的变量,以便引用计数也适用于此。
另一种方法是继承TInterfacedPersistant而不是TInterfacedObject以避免引用计数。
解释代码中发生的事情:
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;