2011-01-13 11 views
7

tuve otro error en mi aplicación causado por el uso descuidado de las interfaces de Delphi. Cuando paso una interfaz a un procedimiento que ignora ese argumento, la instancia nunca se libera. Vea el siguiente ejemplo simple:La referencia de interfaz no utilizada no se destruye

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. 

¿Puede explicar qué va mal con el contador de referencia? ¿Puede dar alguna práctica recomendada/guía (como "Nunca crear una instancia interconectada dentro de una llamada de función [si no sabe qué ocurre dentro]).

La mejor solución que se me ocurre para este ejemplo es escribir un método de plantilla de la base de clase que guarda la instancia prueba superada y llama a un método abstracto DoUseTestOrNot.

EDITAR Delphi 2010

+0

¿Qué versión de Delphi es esto? –

+1

lo siento, es Delphi 2010 – hansmaad

+0

No importa, es un error independientemente de la versión. esperar hasta delphi ex 2? Cheers – APZ28

Respuesta

8

Es una manifestación diferente de los errores here.
Agregaré esto al informe de control de calidad.

Esto ya no se reproduce en la actualización 1 de Delphi XE.

--jeroen

+0

solo otro error, grrr – hansmaad

+0

Para la regresión: ¿me pueden enviar un programa de consola completamente funcional (.dpr) mostrando la pérdida de memoria en Delphi 2010 - preferiblemente con FastMM? Cualquier cosa en pluimers dot com funciona, solo comience con mi nombre. De esa forma puedo descartar cualquier error tipográfico que hice al compilar el código anterior. –

8

Añadir un gUID a que la declaración ITest

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

Cambiar el bucle a esta

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

El GUID es NECESARIO para poder utilizar as

Test.Create as ITest hace que el compilador para agregar la liberación en el que el objeto creado se sale del ámbito.

+0

+1; Esta es una buena solución hasta que se solucione el error. –

+0

Y: está solucionado en Delphi XE o Delphi XE actualización 1. –

+0

Gracias por esta solución. ¿Hay alguna entrada de menú o botón para insertar el GUID? Siempre me olvido del atajo, ya que nunca uso GUID (siempre trato de evitar como y es etc.). – hansmaad

Cuestiones relacionadas