Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 04, 2025 14:17

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Destruktor/Kontruktor abbrechen...
BeitragVerfasst: Fr Mai 01, 2009 17:11 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
Hallo,

Wie kann ich einen Destruktor / Konstruktor abbrechen?

Als Beispiel für einen Destruktorabbruch:
Wenn der Benutzer das Programm beendet, dann soll er gefragt werden ob er die Änderungen vorher noch speichern will, dies ist kein Problem.
ABER er soll auch die Möglichkeit haben, den Vorgang abzubrechen: wie kann ich also dafür sorgen, das die Beendung des Programmes zurückgenommen wird?
EXIT funktioniert NICHT!!!

Als Beispiel für den Konstruktorabbruch:
Bei der Erstellung einer Textur wird im Konstruktor das Format überprüft, ob es unterstützt wird bzw. ob ich eine Konvertierung für OpenGL eingebaut habe.
Wie kann ich da den Konstruktor abbrechen?
EXIT funktioniert hier ebenfals nicht und "Destroy" löst eine Zugriffsverletzung aus. Als Idee hätte ich diese Textur irgendwie erst nach Beendigung des Konstruktors zu zerstören, aber mir fällt keine passende Methode dazu ein.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 01, 2009 17:31 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Exception werfen?

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 01, 2009 18:17 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Jan 31, 2007 18:32
Beiträge: 150
Programmiersprache: Pascal
das mit destroy ließe sich lösen indem du Destroy bei allen betreffenden Klassen mit einer anderen Methode aufrufst

Code:
  1.  
  2. TMyClass = class
  3.   BeforeDestroy : procedure; bzw procedure of Object; musst du gucken was besser in deinen Code passt
  4. End;
  5.  
  6. procedure SaveWaring;
  7. Begin
  8.   // Hier würde dann deine Speichern-Abfrage hinkommen
  9. End;
  10.  
  11. procedure TMyClass.Bla;
  12. Begin
  13.   if Assigned(BeforeDesroy) then BeforeDestroy;
  14.   Destroy;
  15.   // an dieser Stelle empfielt es sich eigenlich Free zu nehmen aber
  16.   //da du von Destroy gesprochen hast...
  17. End;
  18.  
  19. var MyClass : TMyClass;
  20.  
  21. Begin
  22.   MyClass := TMyClass.Create;
  23.   MyClass.BeforeDestroy := SaveWarning;
  24.   MyClass.Bla; // hier wird die klasse wieder freigegeben
  25. End;
  26.  


Wenn du die VLC Application Klasse benutzt brauchst du daran nichts mehr zu ändern diese sollte das eigentlich schon von haus aus können(bin mir aber net sicher könnte auch das VLC Fenster gewesen sein)
zu dem Create mir fällt nichts anderes ein als

Code:
  1.  
  2. TMyClass = class;
  3. class function CreateIfSupported : TMyClass
  4. End;
  5.  
  6. class function TMyClass.CreateIfSupported : TMyClass;
  7. Begin
  8.   Result := nil;
  9.   if not Supported then Exit;
  10.   Result := TMyClass.Create;
  11. End;
  12.  


Ich hoffe das hilft weiter mfg FrenK[/pascal]


Zuletzt geändert von FrenK am Fr Mai 01, 2009 22:33, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 01, 2009 18:39 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Uhm. Wenn du mit der VLC arbeitest und es sich hierbei um den Klick auf das X einer Form handelt, dürfte das CloseQuery-Event (oder heißt es OnClose?) genau das sein, was du suchst.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 01, 2009 20:41 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Zu den Constructoren hab ich folgendes gefunden:

Code:
  1.  
  2. type TTest = class
  3.      public
  4.       constructor Create; overload;
  5.       class function Create(doit:Boolean): TTest; overload;
  6.      end;  
  7.  
  8. implementation
  9.  
  10. constructor TTest.Create;
  11. begin
  12.   raise EAbstractError.Create('Please use the other constructor');
  13. end;
  14.  
  15. class function TTest.Create(doit:Boolean): TTest;
  16. begin
  17.   if doit then
  18.     Result:=inherited Create
  19.   else
  20.     Result := nil;
  21. end;
  22.  


Da ist zwar trotzdem noch eine Exception drin, allerdings nur um zu ermahnen das "richtige" Create zu verwenden, weil man das ursprüngliche Create nicht einfach löschen kann.
Ansonsten scheint es zu funktionieren.
Das "inherited Create" kann man denke ich dann auch gegen einen eigenen Constructor z.B. im "private"-Teil ersetzen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 01, 2009 21:23 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Es hindert einen auch nichts daran, einen zweiten Konstruktor zu deklarieren.
Soweit ich weiss wird der Speicher des Objektes aber auch wieder freigegeben, wenn in Create ne Exception geworfen wurde. Wenn ich mich irre... Könnte man das ganze über einen einigermaßen guten Stil in Destruktor und Konstruktor ausgleichen. D.h. bevor eine Exception auftreten kann/soll alle Felder des Objektes, die Pointer o.ä. beeinhalten, auf nil setzen. Und im Destruktor diese dann nur, wenn sie gleich nil sind freigeben, bzw. bei TObject-Nachfahren (also generell bei allen Objekten) die Free-Methode nehmen. Die prüft das automatisch (sollte man sowieso immer verwenden anstatt direkten aufruf von Destroy).

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Mai 01, 2009 22:07 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Das Create wird erst dann aufgerufen, wenn deine Instanz bereits erstellt wurde. Der Konstruktor dient nur dazu de Member deiner Klasse zu initialisieren. Eine Exception innerhalb des Konstructors sorgt dafür, dass der Destruktor aufgerufen wird und deine Instanz aus dem Speicher entfernt wird. Also falls du dort andere Dinge wieder löscht, dann pass auf dass da kein Scheiß passiert. Wie Lord schon sagte. Alles was problematisch ist im Konstrukter auf nil setzen. Wobei Member von Klassen eigentlich immer nil sind. Allerdings Exceptions solltest du nur dann werfen, wenn es sich wirklich um eine Ausnahme handelt. Also in der Regel braucht man Exceptions im Konstruktor nur dann wenn sowieso irgendwie schon alles im Eimer ist. Da solltest du meiner Meinung nach immer einen anderer Weg bevorzugen.

OnCloseQuery und OnClose: Das gibts Beides. ;) OnCloseQuery wird vor OnClose aufgerufen. Wenn OnCloseQuery bereits false ergibt wird das beenden abgebrochen.

[edit] Du kannst natürlich auch mehrere Konstruktoren in einer Klasse erstellen. Also das was du da hast sieht für mich eher nach so etwas aus. Du kannst auch Methoden vitual (abstract) machen. Dann kannst du die Methoden in späteren Klassen implementieren.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mai 02, 2009 09:40 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Um auch mal meinen Senf dazu zu geben:
Im Destruktor zu prüfen, ob die Änderungen gespeichert werden sollen bzw. ob das Beenden abgebrochen werden soll, halte ich für den falschen Weg. Das sollte schon vorher passieren. Also bevor .Destroy überhaupt aufgerufen wird.
Beim Destruktor muss man sich darauf verlassen können, dass er ordnungsgemäß durchläuft und keine Geschäftslogik enthält.

Wie wär's denn alternativ hiermit?:
Code:
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes, SysUtils;
  7.  
  8. type
  9.   {* Classes implementing this interface are able to report whether they have
  10.      unsaved changes and allow for a more specific handling of their
  11.      destruction. }
  12.   ISaveable = interface
  13.     {* Saves the state of the implementing class }
  14.     procedure Save;
  15.  
  16.     {* Returns true if the component has unsaved changes. }
  17.     function hasUnsavedChanges: boolean;
  18.  
  19.     {* Handles the shutdown of this class. If it has unsaved changes, it will
  20.        allow the user to choose between various closing strategies such as
  21.        [Save And Close], [Dismiss And Close], [Cancel]. }
  22.     procedure handleClose;
  23.   end;
  24.  
  25.   { TFancyGUIComponent }
  26.  
  27.   TFancyGUIComponent = class(ISaveable)
  28.   private
  29.     procedure CloseAndSave;
  30.  
  31.   public
  32.     // ISaveable
  33.     procedure Save;
  34.     function hasUnsavedChanges: boolean;
  35.     procedure handleClose;
  36.   end;


Denke, das gibt schon ne Idee, wie man's machen könnte. Kerngedanke ist schlicht, dass, wenn man .Free bzw. .Destroy aufruft, es schon feststeht, dass die Klasse nun auch wirklich freigegeben wird.

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mai 02, 2009 13:43 
Offline
DGL Member

Registriert: Sa Okt 18, 2008 11:59
Beiträge: 180
Also erstmal danke für die Zahlenmässig großen Hinweise.

Also ich hatte beim Formular OnClose verwendet, aber OnCloseQuery ist dafür wohl besser geeignet (das bestätigt letztlich auch die eingebaute Hilfe).
Damit wäre das Problem mit dem Destruktor gelöst.

Zu dem Konstruktor: ich soll also einfache eine "künstliche" Exception auslösen um den Konstruktor zu stoppen? Sieht doch blöd aus... was ist wenn ich die Exception mit Try-Except abfange, damit der Nutzer davon nichts merkt? Wird dann immernoch das Objekt erstellt?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mai 02, 2009 14:09 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Sobald du eine Exception im Konstruktor hast ist das Objekt weg, da dann der Destruktor aufgerufen wird. Mit try except kannst du dann verhindern, dass die Exception angezeigt wird. Aber das halt ich für den falschen Weg. Exceptions sind Ausnahmen. Die sollten nur ausgelöst werden, wenn wirklich was im Argen ist. Wenn es nur eine Statusinformation ist, dann ist das nicht die feine Englische.

Alternativ zum Abschießen deine Konstruktors kannst du a) vorher überprüfen ob deine Klasse erstellt werden soll oder b) du erstellst die Klasse rufst eine Methode auf mit der du erfragen kannst, ob das unterstützt wird was du haben willst. Und wenn nicht, dann löscht du die Instanz wieder.

Je nachdem was du für dieses erfragen brauchst kannst du damit auch Klassenfunktionen nehmen. Die benötigen keine erstellte Instanz. Dürfen aber auch nicht auf Member zugreifen.



PS: Exceptions im Destruktor ändern glaube ich auch nicht daran, dass das Objekt gelöscht wird. Das wird es meiner Meinung nach in jedem Fall sobald Destroy/Free aufgerufen wird.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.009s | 14 Queries | GZIP : On ]