![]() |
Referenz Verwaltung
Hi Ihr Guten!
Es geht um Referenzen(Pointer) auf Instanzen die noch auf die Instanzen zeigen wenn die Instanzen schon freigegeben sind. (Der Speicher freigegeben ist) Habe warscheinlich ein grundsätzliches Problem zu lösen. Ich lass am besten mal den Code sprechen, der sagt mehr als Worte und wenn Ich hier lange rede dann meißt eh nur um meinen Kopf und Kragen.
Delphi-Quellcode:
Und klar kann ich so nicht herrausfinden ob da noch Zugriffsrechte bestehen weil die Referenz ja bloß ein ahnungsloser Pointer ist... KlasseB.VarX möchte doch bitte NIL sein. Deswegen://type TMeinObject = class(TObject) public VarX : TMeinObject; end; KlasseA : TMeinObject; KlasseB : TMeinObject; //implmnt... KlasseA := TKLasseA.Create; KlasseB := TKLasseB.Create; KlasseB.VarX := KlasseA; KlasseA.VarX := KlasseB; FreeAndNil(KlasseA); if (Assigned(KlasseB.VarX)) then begin ShowMessage('It is assigned... this did not help you sir.'); end;
Delphi-Quellcode:
Damit das jetzt alles brav implementiert wird und alle Klassen von denen Ich auch Referenzen erzeuge Ihre Referenzen selbst verwalten hatte Ich jetzt vor ein IInterface zu verwenden, das habe ich aber noch nie verwendet.
TMeinObject = class(TObject)
public VarX : TMeinObject; ReferenzListe : TList; procedure FreeNotification(Sender : TObject); constructor Create; destructor Destroy; override; end; var KlasseA : TMeinObject; KlasseB : TMeinObject; implementation {$R *.dfm} procedure wayne... begin KlasseA := TKLasseA.Create; KlasseB := TKLasseB.Create; KlasseB.VarX := KlasseA; KlasseA.ReferenzListe.Add(KlasseB); KlasseA.VarX := KlasseB; KlasseB.ReferenzListe.Add(KlasseA); FreeAndNil(KlasseA); if (Assigned(KlasseB.VarX)) then begin ShowMessage('It is assigned... this did not help you sir.'); end; end; constructor TMeinObject.Create; begin ReferenzListe := TList.Create; end; destructor TMeinObject.Destroy; var I: Integer; begin // Referenzlisten Einträge Nillen for I := 0 to ReferenzListe.Count - 1 do begin TMeinObject(ReferenzListe[I]).FreeNotification(Self); end; ReferenzListe.Free; inherited; end; procedure TMeinObject.FreeNotification(Sender: TObject); begin if Sender = VarX then VarX := nil; end; end.
Delphi-Quellcode:
Bevor Ich jetzt anfange zu Programmieren wollte Ich noch mal hier nachfragen ob es üblich ist so mit dem Problem umzugehen oder ob es etwas viel besseres / cooleres gibt wie man jetzt am besten einen solchen Referenzmanager aufbaut.
unit ReferenzVerwaltungsInterface;
interface type IReferenceManager = interface(IInterface) end; implementation end. Grüße. |
AW: Referenz Verwaltung
Wenn du Objekte an mehreren Stellen referenzierst, sind Interfaces eine gute Möglichkeit das zu lösen.
Dafür muss man natürlich dafür sorgen, dass die durch die Interfaces gekapselten Objekte nicht von anderen Sachen abhängig sind, die es dann nicht mehr gibt. Dieses Problem kann es bei der Mischung von Objektreferenzen und Interfaces relativ schnell geben. An der Stelle verweise ich einmal auf das ![]() ![]() Ich persönlich kann den Ideen in der Ausprägung zwar nicht ganz so viel abgewinnen, weil sie mir zu weit gehen, aber andere finden das so gut, dass ich es dennoch erwähne. :wink: Was du davon hältst findest du am besten selbst heraus. :wink: |
AW: Referenz Verwaltung
Was du da vorhast ist so etwas wie die Vorstufe zu einer
![]() Ich meine man sollte das entweder richtig oder gar nicht machen. Im Falle von Delphi, das keinen Garbage Collector besitzt, würde ich auf solche Tricks wie Smart Pointer komplett verzichten. Stattdessen benötigt man eine bestimmte (geistige) Einstellung, wie man mit Objekten oder Resourcen ganz allgemein umzugehen hat. Wann immer ein Objekt erzeugt wird entsteht auch eine Verpflichtung das Objekt später wieder mit Free freizugeben. So nach dem Motto: "Wer das Essen bestellt hat muss nachher auch abspülen" Wenn in einem Formular ein Objekt erzeugt wird, dann hat das Formular den Besitz (Ownership) übernommen und damit auch die Verpflichtung sich um das Objekt zu kümmern. Es ist aber auch möglich, diese Verpflichtung gezielt abzutreten.
Delphi-Quellcode:
Bei Komponenten tritt diese Abgabe der Verantwortung bzw. Ownership ganz explizit zu Tage.
var
list : TObjectList; x : TMeineKlasse; begin list := TObjectList.Create({OwnsObjects=}True); x := TMeineKlasse.Create; list.Add(x); // TObjectList sorgt für die spätere Freigabe von x Man gibt im Konstruktor einfach den Owner an und der Owner wird sich schon um die Freigabe kümmern. Jetzt ist eine Sache noch ganz wichtig Keine globalen Objekt-Variablen verwenden! Bei globalen Variablen hat niemand die Verantwortung übernommen; daher kommen die Probleme bei der Freigabe. Wenn du alle deine globalen Variablen eliminierst, werden auch deine Probleme mit der Freigabe verschwinden. |
AW: Referenz Verwaltung
Zitat:
Zitat:
Delphi-Quellcode:
Wo ist das Problem?
finalization
MeinGlobalesObjekt.Free; end. |
AW: Referenz Verwaltung
Zitat:
DAS hier ist ein Trick (in dem die Referenzzählung eines Interface ausgenützt wird):
Delphi-Quellcode:
unit UAutoRelease;
interface {************************************************************************** * NAME: AutoRelease * DESC: Gibt das übergebene Objekt automatisch beim Verlassen der * aktuellen Funktion frei. * PARAMS: obj: TObject * RESULT: IUnknown * * Hilfsfunktion, um Objekte automatisch beim Verlassen der aktuellen * Funktion freizugeben. * Damit kann man sich manche try .. finally Blöcke sparen. * Beispiel: * procedure xyz; * var sl: TStringList; * t : IUnknown; * begin * sl := TStringList.Create; * t := AutoRelease(sl); * sl.LoadFromFile('c:\autoexec.bat'); * ... * // sl.Free wird nicht mehr benötigt!!! * end; *************************************************************************} function AutoRelease(obj: TObject): IUnknown; implementation type TAutoReleaseObject = class(TInterfacedObject, IUnknown) private FObject: TObject; public constructor Create(obj: TObject); destructor Destroy; override; end; constructor TAutoReleaseObject.Create(obj: TObject); begin inherited Create; FObject := obj; end; destructor TAutoReleaseObject.Destroy; begin FObject.Free; inherited; end; function AutoRelease(obj: TObject): IUnknown; begin Result := TAutoReleaseObject.Create(obj); end; end. Zitat:
Manchmal lässt es sich nicht vermeiden ein Objekt global anzulegen, aber jedes globale Objekt erzeugt auch Probleme wie schlechte Testbarkeit. Wenn Projekte an Umfang zunehmen und Hunderte von Units haben ist jedes globale Objekt eine ![]() |
AW: Referenz Verwaltung
Zitat:
Zitat:
Zitat:
|
AW: Referenz Verwaltung
Zitat:
Zitat:
![]() |
AW: Referenz Verwaltung
Eigentlich hat das nichts mit globalen Variablen zu tun.
Es kann einfach sein, dass man das selbe Objekt an zwei verschiedenen Stellen verwendet, wobei es von der einen Stelle freigegeben wird. Die andere Stelle kriegt davon aber nichts mit und hat keine Möglichkeit zu überprüfen, ob das Objekt noch existiert, weil Assigned nur den Pointer auf nil prüft. Für den Fall, dass man ein Objekt nur an einer einzigen Stelle verwendet, gibt es FreeAndNil, aber bei mehreren, unabhängige Referenzen hilft das nichts. Mal unabhängig davon, dass man immer leicht alles pauschal als „schlechtes Design“ abtun kann, ist das irgendwie asymmetrisch. Man kann das Problem natürlich „klassisch“ mithilfe eines Observer-Patterns o.ä. angehen (so ähnlich wie es die VCL afaik auch macht), aber das ist erstens umständlich und zweitens wieder eine potenzielle Fehlerquelle, weil man jedes mal darauf achten muss, manuell einen Observer hinzuzufügen oder zu entfernen. Ein Smart-Pointer automatisiert das Prozedere einfach nur und wäre daher aus meiner Sicht eine Verbesserung – schlechtes Design gibt es mit und ohne Smart Pointer. Aber mit Smart-Pointer hat man zumindest eine Fußangel weniger, an der es knallen kann. Und an dieser Stelle muss ich natürlich noch mal auf meine ![]() ![]() |
AW: Referenz Verwaltung
Zitat:
Der Entwickler muss eben genau die Lebenzeiten seiner Objekte unter Kontrolle halten. Wenn man sich die Lebenszeit eines Objekts als Rechteck vorstellt, dann besteht die Kunst darin, die Rechtecke so ineinander zu schachteln, dass sich die Grenzen nicht überschneiden. Wenn es ein Objekt A gibt, dass von Objekt B und C benützt wird, dann wird einfach ein Objekt D benötigt, dass alle 3 Objekte in der richtigen Reihenfolge erzeugt und zerstört. Und Probleme entstehen auch dadurch, dass häufig nicht erkannt wird, dass dieses Objekt D benötigt wird. Und wenn Objekt A von B und C benötigt wird, dann wird A eben vor B und C erzeugt und nach B und C zerstört. Globale Objekte stören diese Ordnung, da sie potentiell länger leben können als das Hauptformular. |
AW: Referenz Verwaltung
ich hatte bereits vor einiger Zeit in einem Thread von stahli (der sich seit längerem intensiv mit diesem Thema auseinanderzusetzen scheint) vorgeschlagen eine weitere Dereferenzierung vorzunehmen. Die "Zeiger" also global zu halten und nur noch Zeiger auf die "Zeiger" zu übergeben. Bei dieser Vorgehensweise müsste IMHO bei korrekter Implementierung alles wie gewünscht funktionieren.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:21 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