Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Freigabe von übergebenen Interface-Instanzen (https://www.delphipraxis.net/190404-freigabe-von-uebergebenen-interface-instanzen.html)

AndyDF 30. Sep 2016 09:12

Delphi-Version: 10 Seattle

Freigabe von übergebenen Interface-Instanzen
 
Habe gerade etwas fest gestellt, von dem ich bisher erwartet hatte, dass es funktioniert. Ich arbeite sehr intensiv mit Interfaces und schaue auch immer, dass ich Objekt- und Interfacereferenzen nicht vermische.
Das heißt, Variable vom Interface-Typ definierten und das Objekt mittels Create der Variable zuweisen. Wenn die Interface-Variable aus dem Scope fällt, wird das Objekt dahinter auch immer schön frei gegeben. So soll das sein!

Jetzt hätte ich erwartet, wenn eine Methode eine Interface-Variable übernimmt, und ich beim Aufruf direkt die neu erstelle Objekt-Referenz übergebe, dass der RefCount und die Freigabe korrekt funktionieren. Dem ist anscheinend nicht so. Im Folgenden mal ein Beispiel-Code. Habe an der entsprechenden Stelle einen Kommentar eingefügt...


Delphi-Quellcode:
type
  IMyInterface = interface(IInterface)
    ['{475ACE39-ECC7-467D-A325-35B2DF22203A}']
    procedure DoSomething;
  end;

  TMyInterface = class(TInterfacedObject, IMyInterface)
  private
    procedure DoSomething;
  public
    destructor Destroy; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure Machwas(const AValue: IMyInterface);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

destructor TMyInterface.Destroy;
begin
  ShowMessage('Free!');
end;

procedure TMyInterface.DoSomething;
begin
  //...
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Value: IMyInterface;
begin
  //Wenn der Aufruf auf diese Weise erfolgt, wird das Objekt NICHT frei gegeben.
  Machwas(TMyInterface.Create);

  //So wird das Objekt korrekt frei gegeben
  Machwas(TMyInterface.Create as IMyInterface);

  //so wird das Objekt auch korrekt frei geben
  Value := TMyInterface.Create;
  Machwas(Value);
end;

procedure TForm1.Machwas(const AValue: IMyInterface);
begin
  AValue.DoSomething;
end;
Ist das logisch? Hätte ich bisher anders erwartet... da mir aber der Speicher voll lief, wurde ich eines besseren belehrt. ;)

Der schöne Günther 30. Sep 2016 09:16

AW: Freigabe von übergebenen Interface-Instanzen
 
Das ist ein abartiger Fallstrick. Das
Delphi-Quellcode:
const
in deiner Methode bedeutet für den Compiler "Die Referenz wird nicht verändert. Ach komm, sparen wir uns gleich die Referenzzählung". Tödlich, wie du siehst.

Ich finde es auch schrecklich, die einzige Hilfe ist sich das eigentlich sinnvolle
Delphi-Quellcode:
const
bei Interface-Argumenten abzugewöhnen.

AndyDF 30. Sep 2016 09:19

AW: Freigabe von übergebenen Interface-Instanzen
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1349294)
Das ist ein abartiger Fallstrick. Das
Delphi-Quellcode:
const
in deiner Methode bedeutet für den Compiler "Die Referenz wird nicht verändert. Ach komm, sparen wir uns gleich die Referenzzählung". Tödlich, wie du siehst.

Ich finde es auch schrecklich, die einzige Hilfe ist sich das eigentlich sinnvolle
Delphi-Quellcode:
const
bei Interface-Argumenten abzugewöhnen.

Hmm... wenn du mir das so schreibst, ist eigentlich logisch. Bin ich klassisch drauf rein gefallen. ;)
Danke für die Info.

mjustin 30. Sep 2016 09:54

AW: Freigabe von übergebenen Interface-Instanzen
 
Ich habe mir das Machwas(TMyInterface.Create); abgewöhnt.

Seitdem funktioniert's :)

Das const lasse ich daher. Es soll m.W. ein paar CPU Anweisungen einsparen.

jaenicke 30. Sep 2016 10:25

AW: Freigabe von übergebenen Interface-Instanzen
 
Das const ist bei häufigen Aufrufen spürbar schneller, ja.

Das direkte Übergeben macht man eben nicht. Wenn man es so schreibt, geht es ja. Das hast du ja jetzt vermutlich auch so:
Delphi-Quellcode:
var
  Value: IMyInterface;
begin
  Value := TMyInterface.Create;
  Machwas(Value);

Fritzew 30. Sep 2016 10:26

AW: Freigabe von übergebenen Interface-Instanzen
 
Ja das ist eine "unschönheit" im Delphi Compiler. Ist nicht konsistent in der Hinsicht. Wurde bei stackoverflow auch schon
hoch und runter diskutiert. Zumindest ein Hint sollte da auftauchen.
http://stackoverflow.com/questions/4...ly-as-const-in
Gruss Fritz
PS: Hallo Andreas :-)

AndyDF 30. Sep 2016 10:36

AW: Freigabe von übergebenen Interface-Instanzen
 
Immerhin geht ja folgendes:

Delphi-Quellcode:
Machwas(TMyInterface.Create as IMyInterface);


Dann muss man nicht unbedingt eine Variable anlegen. Allerdings muss man dran denken.... :?

Gruß Andreas
PS: Hallo Fritz. :-D

Stevie 30. Sep 2016 10:41

AW: Freigabe von übergebenen Interface-Instanzen
 
In diese Falle sind schon Generationen von Delphi Entwicklern getappt:

http://qc.embarcadero.com/wc/qcmain.aspx?d=90482
https://quality.embarcadero.com/browse/RSP-10100
https://quality.embarcadero.com/browse/RSP-15797

Aber trotzdem wird es von den Verantwortlichen leider immernoch wegdiskutiert:

https://plus.google.com/+StefanGlien...ts/SM1oVCNa98q

Mavarik 30. Sep 2016 12:00

AW: Freigabe von übergebenen Interface-Instanzen
 
Wenn ich keine Factory für die Klasse habe, mache ich es einfach so...

Delphi-Quellcode:
type
  TMyInterface = class(TInterfacedObject, IMyInterface)
  private
    procedure DoSomething;
  public
    destructor Destroy; override;
    Class Function Construct : IMyInterface;
  end;

implementation


procedure TForm1.Button1Click(Sender: TObject);
begin
  Machwas(TMyInterface.Construct);
end;
Und läuft...

Fritzew 30. Sep 2016 12:11

AW: Freigabe von übergebenen Interface-Instanzen
 
Was machst Du dann bei Parametern im Constructor? Alles doppelt pflegen?
Und wie gewährleistest Du das die Benutzer Deiner Klasse das auch so anwenden?


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:17 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz