2011-01-13 45 views
7

我的应用程序由于不小心使用Delphi接口而导致另一个错误。当我将一个接口传递给忽略该参数的过程时,实例永远不会被释放。请看下面的简单例子:未使用的接口引用不会被破坏

ITest = interface 
    procedure Test; 
end; 

Tester = class(TInterfacedObject, ITest) 
public 
    procedure Test; 
end; 

Base = class 
public 
    procedure UseTestOrNot(test : ITest); virtual; abstract; 
end; 

A = class(Base) 
public 
    procedure UseTestOrNot(test : ITest); override; 
end; 

B = class(Base) 
public 
    procedure UseTestOrNot(test : ITest); override; 
end; 

{ A } 

procedure A.UseTestOrNot(test: ITest); 
begin 
    test.Test(); 
end; 

{ B } 

procedure B.UseTestOrNot(test: ITest); 
begin 
    WriteLn('No test here'); 
end; 

// -------- Test --------------------------------------- 
var 
    list : TObjectList<Base>; 
    x : Base; 
    t : ITest; 
begin 
    ReportMemoryLeaksOnShutdown := true; 

    list := TObjectList<Base>.Create; 
    list.Add(A.Create); 
    list.Add(B.Create); 

    // 1 x Tester leak for each B in list: 
    for x in list do 
     x.UseTestOrNot(Tester.Create); 

    // this is ok 
    for x in list do 
    begin 
     t := Tester.Create; 
     x.UseTestOrNot(t); 
    end; 

    list.Free; 
end. 

你能解释一下引用计数器出了什么问题吗? 你可以给任何最佳做法/指导方针(如“绝不在函数调用内创建一个接口实例[如果你不知道里面发生了什么])

我能想到的这个例子的最佳解决方案是写在Base类的模板方法,节省了通过测试的实例,并调用一个抽象DoUseTestOrNot方法。

编辑 德尔福2010

+0

什么版本的Delphi是这样的? – 2011-01-13 14:50:25

+1

对不起,这是德尔福2010 – hansmaad 2011-01-13 14:51:41

+0

无所谓,它是一个错误,无论版本。等到delphi ex 2?欢呼声 – APZ28 2011-01-13 18:09:57

回答

8

这是一个不同的错误 here的表现形式。
我会将此添加到QC报告中。

这不会在Delphi XE更新1中重现。

- jeroen

8

添加一个GUID你ITEST声明

ITest = interface 
['{DB6637F9-FAD3-4765-9EC1-0A374AAC7469}'] 
    procedure Test; 
end; 

循环改成这样

for x in list do 
    x.UseTestOrNot(Tester.Create as ITest); 

GUID是neccesary能够使用as

Test.Create as ITest使编译器添加这些创建的对象超出范围的释放。