![]() |
Delphi-Version: 2010
Problem mit Objektfreigabe
Ich habe da wohl ein kleines Problem mit der Freigabe von Objekten, bei dem ihr mir sicher helfen könnt.
Mir ist ein Programm in die Hände gelegt worden, bei dem in einer Klasse in einer Klassenfunktion eine globale Variable iniziiert wird. Ungefähr so:
Delphi-Quellcode:
Jetzt gibt es haufenweise Stellen, an denen TMuster.GetMuster() aufgerufen wird und ich weiß nicht genau wann der erste, entscheidende Aufruf stattfindet.
TMuster= class(TObject)
public //... end; //... var Muster: TMuster; implementation //... class procedure TMuster.GetMuster(); begin if not assigned(Muster) then Muster := TMuster.Create; //... Also vorweg: ich weiß, dass globale Variablen nicht so der Hit sind und ich auch schon einen Haufen an globalen Funktionen, Variablen und Konstanten an eine Klasse geklebt habe, aber dieses Objekt bereitet mir noch Kopfschmerzen. Meine Frage ist, wie ich am elegantesten das Dilemma löse, dass ich beim Beenden des Programms immer Speicherfehler angezeigt bekomme? Bitte nicht solche Antworten geben wie "Tja, da musst du dein Programm wohl neu schreiben". Würde es etwas bringen, wenn ich TMuster von TComponent ableite? Soll ich den Destruktor der Mainform verwenden, um
Delphi-Quellcode:
auszuführen?
if assigned(Muster) then Muster.free;
Kann ich direkt in TMuster so etwas wie
Delphi-Quellcode:
im Destruktor verankern?
Self.Free
Wie würdet ihr vorgehen? |
AW: Problem mit Objektfreigabe
Herzlich willkommen in der DP :dp: :dp:
Punkt 1: Schau dich mal nach ![]() Zitat:
Zitat:
Und noch was: Eventuell ist die Prüfung einfacher, wenn du Muster mit nil initialisierst. Dann kannst du nämlich auf ungleich nil prüfen und weißt dann, dass ein Objekt existiert. Bernhard |
AW: Problem mit Objektfreigabe
Zitat:
Delphi-Quellcode:
ist eher nutzlos, da .Free dieses intern auch prüft.
if assigned(Muster) then
Wurde die Variable vorher nicht auf NIL initialisiert, wenn kein Objekt (mehr) drin ist, dann bringt soeine Prüfung auf NIL/Assigned nichts. |
AW: Problem mit Objektfreigabe
Deshalb ist es wichtig immer
Delphi-Quellcode:
statt
FreeAndNil( <Instanz>);
Delphi-Quellcode:
zu verwenden
<Instanz>.Free;
|
AW: Problem mit Objektfreigabe
Du könntest im Destructor prüfen, ob Deine Objektinstanz Deinem globalen "Muster" entspricht...
Delphi-Quellcode:
destructor TMuster.Destroy;
begin if Muster = Self then Muster := nil; inherited; end; Dadurch wird die Verbindung gelöst, egal wann und wie die Instanz aufgelöst wird. FreeAndNil ist dann (in dem Fall) nicht nötig. |
AW: Problem mit Objektfreigabe
Zitat:
Die Meldung lautet übrigens so: Zitat:
Zitat:
Zitat:
Zitat:
Damit brauche ich fremde Objekte nicht belasten. Das werde ich als erstes ausprobieren. Schon einmal danke! |
AW: Problem mit Objektfreigabe
Zitat:
![]() Objekte (und Referenzen darauf) musst Du selbst auf nil setzen (oder eine Lösung selbst implementieren). Delphi macht das (leider) nicht automatisch. |
AW: Problem mit Objektfreigabe
Hi,
wenn ich es richtig verstehe, soll es in der Anwendung nur eine Instanz deines Objektes geben. Und wenn es an mehreren Stellen gebraucht wird, spricht eigentlich nichts gegen globale Funktionen. Ich wüde es dann z.B. so machen:
Code:
Im Programm benutze ich nur die Funktion Muster.
interface
type TMuster = class(TObject) public destructor Destroy; override; end; function Muster: TMuster; implementation Uses SysUtils; var FMuster: TMuster = nil; function Muster: TMuster; begin if not Assigned(FMuster) then FMuster := TMuster.Create; Result := FMuster; end; destructor TMuster.Destroy; begin if FMuster = Self then FMuster := nil; inherited Destroy; end; initialization finalization if Assigned(FMuster) then FMuster.Free; end. Die Funktion Muster als Klassenmethode würde genauso funktionieren. Aber ich spare mir lieber den zusätzlichen Schreibaufwand. Frank |
AW: Problem mit Objektfreigabe
Also es handelt sich hier um das
![]()
Delphi-Quellcode:
Durch die Verwendung der Klassenfunktion SingleInstance wird klar, dass es sich hier um ein Singleton handelt.
implementation
var _Muster:TMuster; // nicht sichtbar ausserhalb der Unit class function TMuster.SingleInstance: TMuster; begin if not Assigned(_Muster) then _Muster := TMuster.Create; Result := _Muster; end; initialization finalization FreeAndNil(_Muster); Später wird die Klasse so verwendet:
Delphi-Quellcode:
Alternativ geht das auch mit With:
procedure Beispiel;
var m : TMuster; begin m := TMuster.SingleInstance; m.irgendwas := ...; // wichtig: NICHT m.Free aufrufen ! end;
Delphi-Quellcode:
Die Lösung mit einer globalen Funktion wie im Vorgängerbeitrag ist auch korrekt,
with TMuster.SingleInstance do
begin irgendwas := ...; aber ich denke, dass meine Lösung es noch besser auf den Punkt bringt. |
AW: Problem mit Objektfreigabe
Das sieht auch nicht schlecht aus.
Zu
Delphi-Quellcode:
noch eine Frage: Kann man _Muster auch als Klassenvariable von TMuster implementieren oder beißt sich dann die Katze in den Schwanz? Ich meine, es ist ja schon toll, dass _Muster nur innerhalb der Unit sichtbar ist, aber noch schöner wäre es, wenn nur die Klasse darauf zugriff hätte. Kann man das noch irgendwie verbinden?
var
_Muster:TMuster; // nicht sichtbar ausserhalb der Unit Ich bin halt einer von denen, die das Wort "global" am liebsten aus ihrem Wortschatz streichen würden (schlechte Erfahrung mit dem Quelltext bei meiner früheren Arbeitsstelle gemacht). Notfalls könnte / müsste ich mich mit einer unitweit-gültigen Variablen zufrieden geben. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:57 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 by Thomas Breitkreuz