Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#19

Re: Plugin-System mit Interfaces und DLLs

  Alt 24. Mär 2006, 05:28
Zitat:
Das ist noch nicht alles. Schau Dir mal mein Demoprogramm an. Da wird das Objekt schon durch den Aufruf einer Prozedur (mit dem Objekt als Parameter) freigegeben, weil eben die Referenzzählung durcheinendergerät.
Nein, die Referenzzählung arbeitet einwandfrei, du machst einfach einen logischen Denkfehler.

Delphi-Quellcode:


procedure TuWas(Intf: IInterface);
// try
// Intf._AddRef <- Referenzcounter ist jetzt +1
begin
end;
// finally
// Intf._Release; <- Referenzcounter ist jetzt 0, ergo Object wird freigegeben
// end;

procedure Test1;
begin
  TuWas(TMyObject.Create); // <- hier impliziter Aufruf, KEINE SICHTBARE Referenzzählung
end;

procedure Test2;
var
  Intf: IInterface;
begin
  Intf := TMyObject.Create;
  TuWas(Intf);
end;
Bei Test1 existiert defakto KEIN lokaler Gültigkeitsbereich für ein Interface. Ergo wenn man ein Object direkt einer Funktion übergibt die ein Interface erwartet und dieses NICHT als const deklariert hat, so wird das Objekt zerstört. Das ist auch logisch, denn betrachte mal den Fall das man TuWas() aufruft mit einem gerade frisch allozierten Interface das später im Program NICHT weiter benutzt wird. Würde der Compiler anderes arbeiten würde dieses allozierte Interface als Speicherleiche übrig bleiben.

Bei Test2 hat man nun explizit das erzeugte Object in eine Interfacevariable gespeichert. Man hat also damit auch explizit eine Scope=Gültigkeitsbereich der offensichtlich die Scope der lokalen Funktion ist, bzw. des lokalen Stacks. Der Compiler kann nun, weil WIR es IHM auch gesagt haben, das Refenerenzecounting benutzen.

Es lässt sich nun streiten ob es nicht richtiger von Borland gewesen wäre für den Testfall in Test1 temporär eine "unsichtbare" lokale Interfacevariable anzulegen die dann gleich nach Rückkehr von TuWas auf nil gesetzt, ergo freigegeben wird. Das ändert nämlich nichts am Sachverhalt das diese Temporäre unsichtbare Interfacevariable wiederum inetwa so aussähe:

Delphi-Quellcode:
  
// try
// Temp := MyObject; // RefCounter == +1
   TuWas(Temp);
// finally
// Temp._Release ; // RefCounter == 0, ergo MyObject.Free
// end;
Du siehst in jedem Falle würde nach dem Aufruf von TuWas() das Objekt immer fregegeben werden.
Das liegt einfach daran das der Compiler nicht das wissen kann was DU einfach mal so vorraussetzt. Nämnlich das FMyObject ein Feld deiner TForm Klasse ist und somit aus DEINER Sicht eine globale Gültigkeit besitzt.
Demo ist aber tatsächlich nicht so, da FMyObject eine Klasse ist und kein Interface !!

Eines ist also sicher, dieses Verhalten ist durchaus logisch, aber leider nicht so richtig dokumentiert.

Fazit: wenn man mit Objekten und Interfaces arbeiten möchte dann sollte man immer mit Hilfe einer lokalen Interfacevariablen, in der man das Object speichert, arbeiten.

Wenn DU also möchtest das dein FMyObject global zur kompletten laufzeit deines TForm auch gültig bleibt dann musst DU dies dem Compiler auch sagen. Inetwa so

Delphi-Quellcode:
type
  TForm1 = class
    FMyObject: TMyObject;
    FMyObjectIntf: IInterface;
  end;

procedure TForm1.FormCreate();
begin
  FMyObject := TMyObject.Create;
  FMyObjectIntf := FMyObject;
end;
Fertig ! Beim zerstören von TForm1 wird FMyObjectIntf automatisch auf nil gesetzt, ergo auch FMyObject.Free aufgerufen.

Gruß Hagen
  Mit Zitat antworten Zitat