2013-04-29 66 views
2

我将创建的对象传递给另一个需要该对象实现的接口的对象的构造函数。作为接口传递对象引用

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和一个内存泄漏 - 整个主窗体已经泄漏。 如果我通过nilTSomeObject构造函数一切都很好。编译器是否通过引用计数释放了FSomeInterface,我不应该在mainForm destructor中尝试释放SomeObject?我怎样才能避免它?

+1

这是如果混合对象和inteface引用会发生什么......可引起非常讨厌的错误。 – jpfollenius 2013-04-29 09:57:00

回答

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; 
+0

哇,很酷的答案! – JustMe 2013-04-29 07:50:52