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/)
-   -   Problem mit Constructor/Destructor (https://www.delphipraxis.net/160052-problem-mit-constructor-destructor.html)

DelphiNerd84 25. Apr 2011 19:58

Delphi-Version: 5

Problem mit Constructor/Destructor
 
hi leute,

bin neu hier im forum und hab gleich ein problem. nach stundenlangen herumprobieren weiss ich nicht mehr weiter :( habe erst seit kurzem angefangen mit klassen zu arbeiten.. und scheitere bereits beim constructor bzw. dem pointer darauf.

Hier erstmal die Unit mit der Class:

Delphi-Quellcode:
UNIT UContainer;
INTERFACE
USES SysUtils;
TYPE
  TContainer=Class
    Private
      FFileName:String;
      Procedure DoSomething;
    Public
      Constructor Create(const FileName:String;AsReadOnly:Boolean);
      Destructor Destroy;override;
  End;
IMPLEMENTATION
Constructor TContainer.Create(constFName:String;AsReadOnly:Boolean);
Begin
 inherited Create;
 If FileExists(FName)Then Begin
  //HandleFile;
  //..
 End Else Destroy
End;
Destructor TContainer.Destroy;
Begin
 inherited Destroy
End;
END.
und dann..
Delphi-Quellcode:
var
  P:Pointer;
Begin
  P:=TContainer.Create('C:\Non-Existing-File.txt',False);
  If P=NIL Then
   ShowMessage('P is NIL')
  Else
   ShowMessage('P is NOT NIL');
  TContainer(P).DoSomething; //..erzeugt Exception!
End;
ich möchte also eine klasse erzeugen, die falls ein problem auftaucht (z.b. nicht existierende datei) sich gleich mittels destructor selbst zerstört. Durch aufruf des destructors sollte doch eigentlich auch der pointer darauf auf nil gesetzt werden? das passiert aber nicht! wie kann man sonst herausfinden ob die klasse noch existiert?

vielen dank!
gruss markus

Zacherl 25. Apr 2011 20:19

AW: Problem mit Constructor/Destructor
 
Die von dir designte Klasse ist höchst "interessant". Ich würde es so lösen:
Delphi-Quellcode:
type
  TContainer = class(TObject)
  private
    FFileName: String;
    FInvalidFile: Boolean;
  public
    procedure DoSomeThing;
    constructor Create(const FileName: String; AsReadOnly: Boolean);
    destructor Destroy;
  published
    property InvalidFile: Boolean read FInvalidFile;
  end;
Dann kannst du im Create prüfen ob die Datei geöffnet werden kann und ansonsten setzt du FInvalidFile auf true. In keinen Fall darfst du im Constructor Destroy aufrufen. Das ist tödlich :D

Sir Rufo 25. Apr 2011 20:26

AW: Problem mit Constructor/Destructor
 
Destroy sollte generell nicht aufgerufen werden, sondern Free.
Im Constructor allerdings auch kein Free ;)

Das Zerstören einer Instanz setzt die Referenzen nicht auf nil.
Darum muss man sich selber kümmern (gibt da ein Delphi-Referenz durchsuchenFreeAndNil aber das würde auch nur diese eine Referenz-Variable auf nil setzen)

jfheins 25. Apr 2011 20:26

AW: Problem mit Constructor/Destructor
 
Auch keine gute Lösung. Denn man bekommt erstmal nichts von dem Fehler mit.

Der "best practise" Weg ist eine Exception im Konstruktor zu werfen. Wenn das passiert, wird das Objekt automatisch wieder aufgeräumt und der Ersteller bekommt eine deutliche Warnung ;)

Zacherl 25. Apr 2011 21:33

AW: Problem mit Constructor/Destructor
 
Da kann man sicherlich geteilter Meinung sein. Ich persönlich mag Klassen, die in ihren Methoden Exceptions werfen absolut nicht. Ich meine normalerweise würde man folgendes machen:
Delphi-Quellcode:
var
  Container: TContainer;
begin
  Containter := TContainer.Create(FileName);
  try
    if not Container.InvalidFile then
    begin

    end;
  finally
    Container.Free;
  end;
end;
Einen spezifischen Fehlercode kann man zur not auch noch irgendwo hinterlegen.

DelphiNerd84 25. Apr 2011 21:37

AW: Problem mit Constructor/Destructor
 
wow, vielen dank für die schnellen antworten! habe schon befürchtet, dass man im constructor nicht gleich wieder den destructor aufrufen darf.. wäre auch zu schön gewesen! werde wohl den code auf mehrere blöcke aufteilen müssen, ähnlich Zacherl es vorgeschlagen hat. ein problem bleibt dennoch: wie kann ich herausfinden ob eine klasse noch existiert? sir rufo sagte bereits, dass das Zerstören die Referenzen nicht auf nil setzt! somit dürfte ja folgendes beispiel NICHT funktionieren..

Delphi-Quellcode:
var
  pFolder:Array Of ^TFolder;

Procedure RemoveFolder(Index:Integer;Recurse:Boolean);
Begin
 //TFolder(pFolder[Index]).DeleteChilds...
 TFolder(pFolder[Index]).Destroy;
End;

und dann später..

Procedure UpdateListItems;
var
  i:Integer;
Begin
 For i:=0To Pred(Length(pFolder))Do
  If TFolder(pFolder[i])=NIL Then RemoveListItem
End;
..aber wie kann ich dann mittels eines Pointers der auf eine Klasse verweist herausfinden ob diese überhaupt noch existiert (ohne eine exception aufzurufen)? naja werde mich wohl oder übel eingehender mit pointer, klassen etc. beschäftigen müssen ;) danke für eure geduld

Sir Rufo 25. Apr 2011 21:42

AW: Problem mit Constructor/Destructor
 
Du könntest aber auch eine
Delphi-Quellcode:
class function
bemühen, die dir ein entsprechendes Objekt zurückliefest oder eben nicht (nil)

mkinzler 25. Apr 2011 21:43

AW: Problem mit Constructor/Destructor
 
Dann halt statt
Delphi-Quellcode:
  finally
    Container.Free;
  end;
Delphi-Quellcode:
  finally
    FreeAndNil( Container);
  end;
Btw nie Destroy direkt aufrufen
Zudem würde ich statt eines arrays eine Liste verwenden

jfheins 25. Apr 2011 22:10

AW: Problem mit Constructor/Destructor
 
Zitat:

Zitat von Zacherl (Beitrag 1096901)
Da kann man sicherlich geteilter Meinung sein. Ich persönlich mag Klassen, die in ihren Methoden Exceptions werfen absolut nicht. Ich meine normalerweise würde man folgendes machen:
Delphi-Quellcode:
var
  Container: TContainer;
begin
  Containter := TContainer.Create(FileName);
  try
    if not Container.InvalidFile then
    begin

    end;
  finally
    Container.Free;
  end;
end;
Einen spezifischen Fehlercode kann man zur not auch noch irgendwo hinterlegen.

OMG :roll:

Zuerst zu dem Fehlercode: Das läuft auf das Gleiche hinaus wie die Property. Man kann sie ignorieren. Und das ist nicht gut. Unter anderem aus diesem Grund gibt es ja gerade die Exceptions, damit nicht jede Klasse ihren eigenen Fehlermechanismus implementieren muss.

Das zweite: Man lässt den Code einfach mal laufen und guckt dann nachher, ob es einen Fehler gegeben hat. Warum nicht vorher prüfen?

Delphi-Quellcode:
var
  Container: TContainer;
begin
   if Fileexists(FileName) then
   begin
      Containter := TContainer.Create(FileName);
      try
         //Was machen
      finally
         Container.Free;
      end;
   end;
end;
Falls die Prüfung vorher tatsächlich nicht gewünscht ist, geht immer noch das hier:
Delphi-Quellcode:
try
   Containter := TContainer.Create(FileName);
except end;

  If Containter=NIL Then
    ShowMessage('Containter is NIL')
   Else
    ShowMessage('Containter is NOT NIL');
   Containter.DoSomething; //..erzeugt Exception!
Wenn der Konstruktor eine Exception wirft, wird die Variable nicht verändert - bleibt also nil.
Der Zugriff am Ende erzeugt aber immer noch eine AV.

DelphiNerd84 25. Apr 2011 22:59

AW: Problem mit Constructor/Destructor
 
es funzt! keine ahnung ob des professionell gelöst ist, aber es geht erstmal

Delphi-Quellcode:
UNIT UContainer;
INTERFACE
USES
  SysUtils;
VAR
  pSelf:Pointer;
TYPE
  TContainer=Class
    Private
      FFileName:String;
      //pLevel:Arary Of ^TLevel;
      //Procedure HandleFile;
      //..
    Public
      Class Function Alive:Boolean;
      Constructor Create;
      Destructor Destroy;override;
      Procedure Assign(const FName:String;AsReadOnly:Boolean);
      Property FileName:String Read FFileName;
      //..
  End;
IMPLEMENTATION
Class Function TContainer.Alive:Boolean;
Begin
 Result:=pSelf<>NIL
End;
Constructor TContainer.Create;
Begin
 inherited Create;
 pSelf:=Pointer(Self);
 //..
End;
Destructor TContainer.Destroy;
Begin
 //..
 pSelf:=NIL;
 inherited Destroy
End;
Procedure TContainer.Assign(const FName:String;AsReadOnly:Boolean);
Begin
 If Not FileExists(FName)Then Begin
  //Destroy
  Free
 End
End;
END.
Delphi-Quellcode:
var
  P:Pointer;
Begin
 P:=TContainer.Create;
 TContainer(P).Assign('C:\Non-Existing-File.txt',False);
 If NOT TContainer(P).Alive Then Begin
  ShowMessage('Klasse existiert nicht mehr!');
  P:=NIL
 End
End;
Danke an alle! ;) und gute n8


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:30 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