2011-01-13 6 views
7

Miałem kolejny błąd w mojej aplikacji spowodowany przez nieostrożne korzystanie z interfejsów Delphi. Kiedy przekazuję interfejs do procedury, która ignoruje ten argument, instancja nigdy nie jest zwalniana. Zobacz następujący prosty przykład:Nieużywany odnośnik interfejsu nie został zniszczony.

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. 

Czy możesz wyjaśnić, co jest nie tak z licznikiem referencyjnym? Czy możesz podać najlepszą praktykę/wytyczne (np. "Nigdy nie twórz instancji z interfejsem wewnątrz wywołania funkcji [jeśli nie wiesz, co dzieje się w środku].)

Najlepsze rozwiązanie, jakie mogę wymyślić dla tego przykładu, to napisać metodę szablonu w klasie bazowej, która zbawia przekazany egzemplarz testowy i wywołuje abstrakcyjną DoUseTestOrNot metody.

EDIT Delphi 2010

+0

Jaka jest wersja Delphi? –

+1

Niestety, to Delphi 2010 – hansmaad

+0

Nie ma znaczenia, jest to błąd niezależnie od wersji. czekać do delphi ex 2? Pozdrawiam: – APZ28

Odpowiedz

8

Jest to inna manifestacja błędów here.
Dodam to do raportu QC.

To nie powtarza się już w Delphi XE update 1.

--jeroen

+0

Kolejny błąd, grrr – hansmaad

+0

Dla regresji: czy możesz wysłać do mnie w pełni funkcjonalny program konsoli (.dpr) pokazujący wyciek pamięci w Delphi 2010 - najlepiej z FastMM? Wszystko w pluvelers dot com działa, zacznij od mojego imienia. W ten sposób mogę wykluczyć wszelkie literówki, które popełniłem w wyniku kompilacji powyższego kodu. –

8

Dodaj GUID dla ciebie oświadczenie iTest

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

Zmień pętlę do tego

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

GUID jest neccesary aby móc korzystać as

Test.Create as ITest sprawia, że ​​kompilator dodać uwalnianie gdzie stworzył przedmiot wykracza poza zakres.

+0

+1; To dobre rozwiązanie, dopóki bug nie zostanie naprawiony. –

+0

I: jest naprawiony w Delphi XE lub Delphi XE update 1. –

+0

Dziękujemy za obejście tego problemu. Czy jest jakiś wpis menu lub przycisk do wstawienia identyfikatora GUID? Zawsze zapominam o skrócie, ponieważ nigdy nie używam identyfikatorów GUID (zawsze staram się unikać jako i jest itp.). – hansmaad