![]() |
Delphi-Version: 2009
Supports ohne out Parameter
Hallo,
Ich werde nicht so recht schlau aus dem was genau bei den folgenden Situationen passiert. Es geht um diese Funktion aus der SysUtils.pas:
Delphi-Quellcode:
Wenn man das unten stehende Programm ausführt, verabschiedet es sich an markierter Stelle #1 mit einer
function Supports(const Instance: TObject; const IID: TGUID): Boolean;
EInvalidPointer Exception (wahrscheinlich beim Freigeben der temporären Variable aus einer anderen Supports() Überladung).
Delphi-Quellcode:
Ändert man das folgende Programm ab und ersetzt die Writeln Aufrufe durch ShowMessage,
program Project38;
{$APPTYPE CONSOLE} uses SysUtils; type IFirst = interface ['{BC927DB0-9B4D-49C4-8460-6714605F4F20}'] end; ISecond = interface ['{F7DBA334-8216-4435-AD56-2E9465CE975B}'] end; TFirstSecond = class(TInterfacedObject, IFirst, ISecond) end; var a: TFirstSecond; f: IFirst; s: ISecond; begin a := TFirstSecond.Create; if Supports(a, IFirst) then Writeln('a supports IFirst'); if Supports(a, ISecond) then // #1 Writeln('a supports ISecond'); if Supports(a, IFirst, f) then Writeln('[out] a supports IFirst'); if Supports(a, ISecond, s) then Writeln('[out] a supports ISecond'); Readln; end. verschwindet dieser Fehler.
Delphi-Quellcode:
Hinzu kommt das der erste Aufruf von Supports() ohne out Parameter, scheinbar
program Project38;
{$APPTYPE CONSOLE} uses Dialogs, SysUtils; type IFirst = interface ['{BC927DB0-9B4D-49C4-8460-6714605F4F20}'] end; ISecond = interface ['{F7DBA334-8216-4435-AD56-2E9465CE975B}'] end; TFirstSecond = class(TInterfacedObject, IFirst, ISecond) end; var a: TFirstSecond; f: IFirst; s: ISecond; begin a := TFirstSecond.Create; if Supports(a, IFirst) then ShowMessage('a supports IFirst'); if Supports(a, ISecond) then ShowMessage('a supports ISecond'); if Supports(a, IFirst, f) then ShowMessage('[out] a supports IFirst'); if Supports(a, ISecond, s) then ShowMessage('[out] a supports ISecond'); Readln; end. die Variable a verändert. Leider reicht mein Assemblerwissen nicht ganz aus um alles nachzuvollziehen was in class function TObject.GetInterfaceEntry(const IID: TGUID): PInterfaceEntry; geschiet. Nach meinem Verständnis müssten alle vier Meldungen angezeigt werden, stattdessen wird nur die erste angezeigt. Vielleicht kann jemand Licht ins Dunkel bringen :) |
AW: Supports ohne out Parameter
Verwende mal TComponent, statt dem TInterfacedObject. [edit] oder TInterfacedPersistent, dessen Name ich ständig vergesse (Dank an Uwe)
Du nutzt das TFirstSecond als Objekt-Instanz, womit es intern keine Interfacereferenz gibt. Suppots greift aber intern über ein Interface zu, womit also eine Interface-Referenz erstellt wird. Bei Freigabe dieser Referenz wird dann das ganze Objekt freigegeben, da es keine weiteren Referenzen gibt. In TComponent wird die Referenzzählung der Interfaces "ignoriert" und diese steuern vorallem nicht die Freigabe. |
AW: Supports ohne out Parameter
Hallo,
ich vermute einfach mal (hab gerade kein Delphi zur Hand), dass Supoorts intern AddRef / Release aufruft. Durch das Release wird dann das Objekt freigegeben und schon knallt's. Eine mögliche Lösung (die viele Probleme vermeidet) ist, immer mit Interfaces zu arbeiten und nie mit dem konkreten Objekt. Alternativ gibt es noch ein Basisobjekt, das die Referenzzählung ausschaltet. Da musst Du aber wissen, was Du tust. Solltest Du aber bei Interfaces immer :) Gruß xaromz |
AW: Supports ohne out Parameter
Die anderen haben es ja schon erklärt. Das Support ohne out-Parameter ruft intern das mit out-Parameter auf, wobei das temporäre Interface beim Verlassen der Funktion freigegeben wird. Da a ein TFirstSecond ist, was von TInterfacedObject abgeleitet wurde, ist der interne Referenzzähler nach dem Create Null. Wenn jetzt die implizite Referenzzählung ein Add/Release ausführt, wird beim Release der Referenzzähler wieder zu Null und die Instanz wird freigegeben. Ab dann zeigt a auf eine nicht mehr existente Instanz.
Wenn du sowohl mit Interfaces als auch mit Objekt-Instanzen arbeiten willst, kannst du statt TInterfaceObject auch TInterfacedPersistent nehmen. |
AW: Supports ohne out Parameter
Danke für die Antworten, das mit Referenzzählung hätte mir auffallen müssen, aber
was ist mit dem zweiten Teil der Frage? Wie und warum genau verändert Supports() die Instanz so das bei dem Aufruf von Supports(a, ISecond) als Rückgabe Wert false rauskommt? |
AW: Supports ohne out Parameter
Zitat:
|
AW: Supports ohne out Parameter
Ich verstehe nicht, weshalb Dir alle raten, nicht TInterfacedObject zu verwenden... Ändere einfach
Delphi-Quellcode:
in
var
a: TFirstSecond;
Delphi-Quellcode:
und alles funktioniert.
var
a: IInterface; |
AW: Supports ohne out Parameter
Zitat:
Delphi-Quellcode:
Nach dem
function Supports(const Instance: IInterface; const IID: TGUID): Boolean;
var Temp: IInterface; begin Result := Supports(Instance, IID, Temp); end;
Delphi-Quellcode:
ist der Referenzzähler von a = 0. Beim ersten Aufruf von Supports wird in der Support-Funktion für Temp ein implizites AddRef und Release ausgelöst, da beim Verlassen der Funktion alle lokalen Interface-Variablen auf nil gesetzt werden. Beim Release springt der Referenzzähler wieder auf 0 und die Instanz wird freigegeben. Danach verweist a nicht mehr auf eine gültige Instanz und es geschehen nicht vorhersagbare Dinge.
a := TFirstSecond.Create
|
AW: Supports ohne out Parameter
Zitat:
|
AW: Supports ohne out Parameter
War im Beispiel der falsche Overload der Funktion - der richtige enthält übrigens eine entsprechende Warnung:
Delphi-Quellcode:
function Supports(const Instance: TObject; const IID: TGUID): Boolean;
var Temp: IInterface; begin // NOTE: Calling this overload on a ref-counted object that has REFCOUNT=0 // will result in it being freed upon exit from this routine. Result := Supports(Instance, IID, Temp); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz