![]() |
Delphi-Version: XE7
Supports(..) liefert Referenz welche AV auslöst
Ich möchte kein konkretes Problem lösen. Ich möchte nur verstehen warum folgender Code mit der Zeile
Delphi-Quellcode:
eine
if castSuccessful then myIntf.doSomething();
Zitat:
Delphi-Quellcode:
program Project3;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething(); end; TMyClass = class(TInterfacedObject, IMyInterface) public constructor Create(); procedure doSomething(); end; procedure justSupportsThings(); var myObject: TObject; myIntf: IMyInterface; castSuccessful: Boolean; begin myObject := TMyClass.Create(); castSuccessful := Supports(myObject, IInterface, myIntf); if castSuccessful then myIntf.doSomething(); end; constructor TMyClass.Create(); begin _AddRef(); // Damit mich das Supports(..) nicht abräumt end; procedure TMyClass.doSomething; begin // nop end; begin try justSupportsThings(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. Mir ist klar, dass im Aurfuf
Delphi-Quellcode:
die letzten beiden Parameter nicht wirklich zusammenpassen, denn
Supports(myObject, IInterface, myIntf);
Delphi-Quellcode:
ist vom Typ
myIntf
Delphi-Quellcode:
.
IMyInterface = Interface(IInterface)
Bedeutet das etwa dass
Delphi-Quellcode:
die Referenz nur soweit "befüllt" wie ich mit der GUID angebe?
Supports(..)
Ich habe mich mit den ganzen Dingen im Hintergrund (VMT, all das) nie beschäftigt... |
AW: Supports(..) liefert Referenz welche AV auslöst
Nur so fürs Protokoll, versuche es mal so
Delphi-Quellcode:
program dp_183554;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething( ); end; TMyClass = class( TInterfacedObject, IMyInterface ) public constructor Create( ); procedure doSomething( ); end; procedure justSupportsThings( ); var myObject: TObject; myIntf: IMyInterface; castSuccessful: Boolean; begin myObject := TMyClass.Create( ); castSuccessful := Supports( myObject, IMyInterface, myIntf ); if castSuccessful then myIntf.doSomething( ); end; constructor TMyClass.Create( ); begin inherited; // Schwachfug // _AddRef(); // Damit mich das Supports(..) nicht abräumt end; procedure TMyClass.doSomething; begin // nop end; begin try justSupportsThings( ); except on E: Exception do Writeln( E.ClassName, ': ', E.Message ); end; readln; end. |
AW: Supports(..) liefert Referenz welche AV auslöst
Natürlich, der Leitsatz aus deiner Signatur greift einfach immer. 8-)
Aber das war mir klar, meine Frage ist ja auch eine andere |
AW: Supports(..) liefert Referenz welche AV auslöst
Supports liefert dir im dritten Parameter einen Zeiger auf die VMT genau des Interfaces, das du abfragst. Da in diesem Fall die Typsicherheit nicht greift, da der Parameter typlos ist, musst du selbst dafür sorgen, daß die Interface-Variable dort auch den passenden Typ hat (nämlich den, den du abfragst).
|
AW: Supports(..) liefert Referenz welche AV auslöst
Ihr müsst ja auch nicht gleich alle auf mir rumhacken :mrgreen:
Dann versuch mal das hier
Delphi-Quellcode:
type
IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething( ); end; TMyClass = class( TInterfacedObject, IInterface, IMyInterface ) // <- Augen auf public constructor Create( ); procedure doSomething( ); end; procedure justSupportsThings( ); var myObject: TObject; myIntf: IMyInterface; castSuccessful: Boolean; begin myObject := TMyClass.Create( ); castSuccessful := Supports( myObject, IInterface, myIntf ); if castSuccessful then myIntf.doSomething( ); // <- beim Eierkauf - Keine Exception mehr :o) end; |
AW: Supports(..) liefert Referenz welche AV auslöst
Hach ja, das alte Problem, dass "vererbte" Interfaces nicht implizit in der Klasse landen...
|
AW: Supports(..) liefert Referenz welche AV auslöst
Hier mal das Originalbeispiel etwas erweitert. Man vergleiche die Reihenfolge der Methodenaufrufe im Source mit der der tatsächlich ausgeführten Methoden.
Delphi-Quellcode:
program Project4;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes; type IMyInterface = interface ['{88DDD9A5-F4BC-47B9-9240-31B1C986F230}'] procedure doSomething(); end; IMyInterface2 = interface ['{D9B8FC6D-2F71-4E31-A5E7-0CCA98146E78}'] procedure doSomeotherthing(); end; TMyClass = class(TInterfacedPersistent, IMyInterface, IMyInterface2) public procedure doSomething(); procedure doSomeotherthing(); end; procedure justSupportsThings(); var myObject: TObject; myIntf: IMyInterface; myIntf2: IMyInterface2; begin myObject := TMyClass.Create(); try if Supports(myObject, IMyInterface, myIntf) then myIntf.doSomething(); if Supports(myObject, IMyInterface2, myIntf2) then myIntf2.doSomeotherthing(); if Supports(myObject, IMyInterface2, myIntf) then myIntf.doSomething(); if Supports(myObject, IMyInterface, myIntf2) then myIntf2.doSomeotherthing(); finally myObject.Free; end; end; procedure TMyClass.doSomeotherthing; begin Writeln('Someotherthing'); end; procedure TMyClass.doSomething; begin Writeln('Something'); end; begin try justSupportsThings(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. |
AW: Supports(..) liefert Referenz welche AV auslöst
Zitat:
Entweder man benutzt nur Interface-Referenzen oder nur Objekt-Referenzen. Nur z.B. bei TComponent-Nachfahren kann man Beides benutzen, da dort die Referenzzählung deaktiviert wurde. |
AW: Supports(..) liefert Referenz welche AV auslöst
@himitsu
![]() Und man kann sich auch eine eigene Interfaced-Klasse bauen, die keine Referenzzählung hat. |
AW: Supports(..) liefert Referenz welche AV auslöst
Zitat:
Delphi-Quellcode:
Das Memory Leak ergibt sich nur bei TComponent als Basisklasse. Mit TInterfacedObject als Basisklasse wird das über Interface verwaltete Feld FInt beim Destroy mit freigegeben, und kein Leak bleibt zurück.
program LeakTest;
uses Classes; type MyInterface = interface end; TMyImplementation = class(TComponent, MyInterface) end; TMyContainer = class(TObject) private FInt: MyInterface; public property Impl: MyInterface read FInt write FInt; end; var C: TMyContainer; begin ReportMemoryLeaksOnShutdown := True; C := TMyContainer.Create; C.Impl := TMyImplementation.Create(nil); C.Free; end. Unter Stackoverflow kann man den Hintergrund dieses Verhaltens detailliert nachlesen. ![]() |
AW: Supports(..) liefert Referenz welche AV auslöst
Sir Rufo:
Drum "z.B." ... halt Alles, wo die Referenzzählung nicht für die Freigabe benutzt wird. @mjustin: Nein, das Leak ist her nur, weil TComponent/TInterfacedObject nicht über die Referenzzählung freigegeben wird, sondern ausschließlich über das Free der Objektinstanz. Das wurde absichtlich so gemacht, damit die Instanzen nur von der VCL verwaltet werden und man dennoch Interfaces benutzen kann (nur für Funktionszugriffe und nicht für die Freigabe). Also bist DU an den Leak Schuld, denn du versuchst ein Interface über die Referenzzzählung freizugeben, welches darüber nicht freigegeben wird. |
AW: Supports(..) liefert Referenz welche AV auslöst
Zitat:
|
AW: Supports(..) liefert Referenz welche AV auslöst
Zitat:
TComponent wird vorwiegend innerhalb der VCL verwendet und Diese gibt ausschließlich ihre Instanzen über Free frei, da es z.B. keine Weak-Referenzen für Objekte gibt, welche bei Freigabe auf nil gesetzt werden. Es wird maximal das in TComponent gekapselte Interface freigegeben, wenn RefCount auf 0 fällt. z.B. bei sowas wie TXMLDokument TVCLAutoObject oder TActiveFormControl (spezielles TActiveXControl), wo die eigentliche Funktion in ein Interface weitergeleitet wird. (siehe IVCLComObject) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:09 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