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/)
-   -   Delphi Problem mit Objektfreigabe (https://www.delphipraxis.net/159484-problem-mit-objektfreigabe.html)

Suboptimierer 30. Mär 2011 10:38

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:
TMuster= class(TObject)
  public
//...
end;
//...
var
  Muster: TMuster;

implementation
//...
class procedure TMuster.GetMuster();
begin
  if not assigned(Muster) then
    Muster := TMuster.Create;
//...
Jetzt gibt es haufenweise Stellen, an denen TMuster.GetMuster() aufgerufen wird und ich weiß nicht genau wann der erste, entscheidende Aufruf stattfindet.
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:
if assigned(Muster) then Muster.free;
auszuführen?
Kann ich direkt in TMuster so etwas wie
Delphi-Quellcode:
Self.Free
im Destruktor verankern?
Wie würdet ihr vorgehen?

rollstuhlfahrer 30. Mär 2011 10:44

AW: Problem mit Objektfreigabe
 
Herzlich willkommen in der DP :dp: :dp:

Punkt 1: Schau dich mal nach Hier im Forum suchenSingleton um. Da müsste eigentlich eine Beschreibung dabei sein, wie man das wieder aus dem Speicher nimmt.

Zitat:

Zitat von Suboptimierer (Beitrag 1091932)
Meine Frage ist, wie ich am elegantesten das Dilemma löse, dass ich beim Beenden des Programms immer Speicherfehler angezeigt bekomme?

Und was ist die Quelle deines Speicherfehlers? Entfernst du das Objekt oder nicht?

Zitat:

Zitat von Suboptimierer (Beitrag 1091932)
Soll ich den Destruktor der Mainform verwenden, um
Delphi-Quellcode:
if assigned(Muster) then Muster.free;
auszuführen?

Schon mal ausprobiert?

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

himitsu 30. Mär 2011 11:11

AW: Problem mit Objektfreigabe
 
Zitat:

Delphi-Quellcode:
if assigned(Muster) then Muster.free;

Delphi-Quellcode:
if assigned(Muster) then
ist eher nutzlos, da .Free dieses intern auch prüft.

Wurde die Variable vorher nicht auf NIL initialisiert, wenn kein Objekt (mehr) drin ist, dann bringt soeine Prüfung auf NIL/Assigned nichts.

mkinzler 30. Mär 2011 11:21

AW: Problem mit Objektfreigabe
 
Deshalb ist es wichtig immer
Delphi-Quellcode:
FreeAndNil( <Instanz>);
statt
Delphi-Quellcode:
<Instanz>.Free;
zu verwenden

stahli 30. Mär 2011 11:22

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.

Suboptimierer 30. Mär 2011 11:28

AW: Problem mit Objektfreigabe
 
Zitat:

Zitat von rollstuhlfahrer (Beitrag 1091935)
Zitat:

Zitat von Suboptimierer (Beitrag 1091932)
Meine Frage ist, wie ich am elegantesten das Dilemma löse, dass ich beim Beenden des Programms immer Speicherfehler angezeigt bekomme?

Und was ist die Quelle deines Speicherfehlers? Entfernst du das Objekt oder nicht?

Bisher wird das Objekt wohl noch nicht entfernt. Bevor ich losmachen wollte, wollte ich mich nur nach dem elegantesten Stil umhören.
Die Meldung lautet übrigens so:
Zitat:

---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:



1 - 12 bytes: Unknown x 1

13 - 20 bytes: UnicodeString x 8

21 - 28 bytes: UnicodeString x 6

29 - 36 bytes: TCriticalSection x 1, TMuster x 4, UnicodeString x 2


---------------------------
OK
---------------------------
Quelle des Fehlers: ?

Zitat:

Zitat von rollstuhlfahrer (Beitrag 1091935)
Zitat:

Zitat von Suboptimierer (Beitrag 1091932)
Soll ich den Destruktor der Mainform verwenden, um
Delphi-Quellcode:
if assigned(Muster) then Muster.free;
auszuführen?

Schon mal ausprobiert?

Bisher noch nicht, weil ich vom Gefühl her dies eher für eine schlechtere Variante halte. Meines Erachtens muss sich das Objekt selbst ums aufräumen kümmern, oder der Aufrufer (in diesem Fall nicht feststellbar) oder die ultimative Lösung: der Garbage Collector.

Zitat:

Zitat von rollstuhlfahrer (Beitrag 1091935)
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.

Was meinst du mit einfacher? Weniger Tipparbeit?

Zitat:

Zitat von stahli (Beitrag 1091946)
Delphi-Quellcode:
destructor TMuster.Destroy;
begin
  if Muster = Self then
    Muster := nil;
  inherited;
end;

Das ist finde ich eine sehr elegante Lösung :thumb:
Damit brauche ich fremde Objekte nicht belasten. Das werde ich als erstes ausprobieren. Schon einmal danke!

stahli 30. Mär 2011 11:52

AW: Problem mit Objektfreigabe
 
Zitat:

Zitat von Suboptimierer (Beitrag 1091948)
Bisher noch nicht, weil ich vom Gefühl her dies eher für eine schlechtere Variante halte. Meines Erachtens muss sich das Objekt selbst ums aufräumen kümmern, oder der Aufrufer (in diesem Fall nicht feststellbar) oder die ultimative Lösung: der Garbage Collector.

Da kommst Du mit Delphi nicht weit. Das Thema wurde hier kürzlich angerissen.
Objekte (und Referenzen darauf) musst Du selbst auf nil setzen (oder eine Lösung selbst implementieren). Delphi macht das (leider) nicht automatisch.

dataspider 30. Mär 2011 12:02

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:
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.
Im Programm benutze ich nur die Funktion Muster.
Die Funktion Muster als Klassenmethode würde genauso funktionieren.
Aber ich spare mir lieber den zusätzlichen Schreibaufwand.

Frank

shmia 30. Mär 2011 13:02

AW: Problem mit Objektfreigabe
 
Also es handelt sich hier um das Singleton Design Pattern.
Delphi-Quellcode:
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);
Durch die Verwendung der Klassenfunktion SingleInstance wird klar, dass es sich hier um ein Singleton handelt.
Später wird die Klasse so verwendet:
Delphi-Quellcode:
procedure Beispiel;
var
  m : TMuster;
begin
  m := TMuster.SingleInstance;
  m.irgendwas := ...;

  // wichtig: NICHT m.Free aufrufen !
end;
Alternativ geht das auch mit With:
Delphi-Quellcode:
with TMuster.SingleInstance do
begin
  irgendwas := ...;
Die Lösung mit einer globalen Funktion wie im Vorgängerbeitrag ist auch korrekt,
aber ich denke, dass meine Lösung es noch besser auf den Punkt bringt.

Suboptimierer 30. Mär 2011 13:27

AW: Problem mit Objektfreigabe
 
Das sieht auch nicht schlecht aus.

Zu
Delphi-Quellcode:
var
  _Muster:TMuster; // nicht sichtbar ausserhalb der Unit
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?
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 12:01 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