2013-04-29 2 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 и утечку памяти - вся основная форма просочилась. Если я прохожу nil в конструктор TSomeObject, все в порядке. Является компилятором, освобождающим FSomeInterface подсчетом ссылок, и я не должен пытаться освободить SomeObject в mainForm destructor? Как я могу избежать этого?

+1

Это то, что происходит, если вы смешиваете объект и inteface ссылки ... может вызвать очень неприятные ошибки. – jpfollenius

ответ

7

TSomeObject унаследован от TInterfacedObject и, таким образом, подсчитывается ссылка. Ваш экземпляр объекта TSomeObject не считается подсчитанным и должен быть удален или заменен переменной интерфейса.

Если вам нужен экземпляр TSomeObject, созданный в FormCreate, вы должны назначить его переменной типа 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

Смежные вопросы