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

Aktuelle Zeit: So Jul 13, 2025 20:49

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



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: [FPC] Anwendung spiel verrückt
BeitragVerfasst: Fr Aug 31, 2007 19:09 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Hi @ll

Ich scheine ja im Moment echt ein Talent dafür zu haben, komische Fehler zu produzieren...

Naja, also folgendes ist hier los: Ich habe meinen Weltmanager, der wiederum ein Unterobjekt Definitionsmanager enthält. Zum ende des Programms will ich (natürlich) den Weltmanager freigeben. Dazu rufe ich folgenden Code auf:
Code:
  1.  
  2. procedure FreeData;
  3. begin
  4.   // ...
  5.   FreeAndNil(World); // World: TworldManager
  6.   / ...
  7. end;
  8.  

FreeData wird definitiv genau einmal aufgerufen, am ende des Programms.

Der Destructor von TworldManager sieht folgendermaßen aus:
Code:
  1.  
  2. destructor TworldManager.Destroy;
  3. begin
  4.   FDefinitions.Destroy; // FDefinitions: TworldDefinitionManager
  5.   inherited Destroy;
  6. end;  
  7.  


Der von TworldDefinitionManager wiederum so:
Code:
  1.  
  2. destructor TworldDefinitionManager.Destroy;
  3. begin
  4.   WriteLn('entered destroy'); // für debugzwecke...
  5.   ClearAll; // Leert die ganzen untenstehenden Listen und gibt die dort gespeicherten Objekte frei.
  6.   FBuildings.Destroy; // FBuildings: TFPList; (TFPList ist sowas wie TList, nur ohne Event handler)
  7.   FEquipments.Destroy;
  8.   FFactors.Destroy;
  9.   FPlanets.Destroy;
  10.   FRaces.Destroy;
  11.   FTechnologies.Destroy;
  12.   FUnits.Destroy;
  13.   FWares.Destroy;
  14.   inherited Destroy;
  15. end;
  16.  


Mein problem ist jetzt, dass der Destructor von TworldManager mehr als 20 mal aufgerufen wird.
Ich habe keine Ahnung, woran das liegt. Dabei ist es egal, ob ich FreeAndNil verwende oder Destroy direkt aufrufe...

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 Aug 31, 2007 21:09 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Sep 02, 2002 15:41
Beiträge: 867
Wohnort: nahe Stuttgart
Wenn du statt Instanz.Destroy; Instanz.Free; verwendest, wird geprüft, ob überhaupt was zum Löschen vorhanden ist. Dann dürfte es auch nicht so schlimm sein, wenn der Destruktor 20mal aufgerufen wird. Obwohl das natürlich ein seltsamer Effekt ist, den ich leider nicht reproduzieren kann.

MfG


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Aug 31, 2007 21:26 
Offline
DGL Member
Benutzeravatar

Registriert: Di Jun 24, 2003 19:09
Beiträge: 732
generell sollte Destroy nie direkt aufgerufen werden... immer .Free verwenden.
Ist aber hier nicht der Grund für den Fehler.

Eventuell beim Destructor die override Direktive vergessen oder die Klassen von möglichen List Klassen (TList, TObjectList,...) abgeleitet die eventuell eine .Clear funktion beim freigeben aufrufen welche dann den destructor für jedes element nochmal aufruft?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Sep 01, 2007 12:51 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Nein leider nicht.

die beiden von mir angesprochnen Klassen sind von TObject abgeleitet. Der Destructor ist overridden, danach habe ich auch schon geschaut.

@WhiteHunter:
Ich habe noch nie gesehen, dass in einem Destructor bei den unterinstanzen kein .Destroy sondern .Free aufgerufen wurde...

Ich habe jetzt den Code nochmal durchgeschaut, nach dem Hinweis auf Clear.
Die Methoden zum Clearen der listen sind jeweils einzeln implementiert, also ClearBuildings, ClearUnits usw usf. Ich habe die jetzt mal alle auskommentiert und siehe da, alles funktioniert (abgesehen von einem Speicherleck, weil die Objekte in den listen nicht mehr freigegeben werden). Nach weiteren experimenten habe ich festgestellt, dass der Fehler in dem Destructor von TworldDefinitionObjectWare, also den dingern, die in FWares drin sind liegen muss. Da TworldDefinitionObjectWare aber keinen Destructor hat, sondern ihn erbt. Die verzweigungen dabei sind einfach zu riesig, ich hänge einfach mal den Source an.

btw.: Wieso ist .pas hier verboten..?
//Edit: Attachment entfernt, läuft ja jetzt -_____-

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


Zuletzt geändert von Lord Horazont am Mi Sep 05, 2007 17:20, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Sep 01, 2007 13:45 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Sep 02, 2002 15:41
Beiträge: 867
Wohnort: nahe Stuttgart
Lord Horazont hat geschrieben:
@WhiteHunter:
Ich habe noch nie gesehen, dass in einem Destructor bei den unterinstanzen kein .Destroy sondern .Free aufgerufen wurde...


Die mancherorts oft zitierte Delphi OH hat geschrieben:
Das folgende Beispiel zeigt eine typische Destruktorimplementierung:

Code:
  1. destructor TShape.Destroy;
  2. begin
  3.   FBrush.Free;
  4.   FPen.Free;
  5.   inherited Destroy;
  6. end;


Die letzte Anweisung ruft den geerbten Destruktor auf, der die geerbten Felder freigibt.

Wenn beim Erstellen eines Objekts eine Exception auftritt, wird das unvollständige Objekt automatisch durch einen Aufruf von Destroy freigegeben. Der Destruktor muss daher auch in der Lage sein, Objekte freizugeben, die nur teilweise erstellt wurden. Da im Konstruktor alle Felder eines neuen Objekts mit Null initialisiert werden, haben Klassenreferenz- und Zeigerfelder in einer unvollständigen Instanz immer den Wert nil. Testen Sie solche Felder im Destruktor immer auf den Wert nil, bevor Sie Operationen mit ihnen durchführen. Wenn Sie Objekte nicht mit Destroy, sondern mit der Methode Free (von TObject) freigeben, wird diese Prüfung automatisch durchgeführt.


Beispiele in der LCL:
Code:
  1. // Graphics.pp, picture.inc, 357ff:
  2. destructor TPicture.Destroy;
  3. begin
  4.   FGraphic.Free;
  5.   inherited Destroy;
  6. end;  
  7.  
  8. // Classes.pp, lists.inc, 507ff:
  9. destructor TThreadList.Destroy;
  10.   begin
  11.     LockList;
  12.     try
  13.       FList.Free;
  14.       inherited Destroy;
  15.     finally
  16.       UnlockList;
  17.       DoneCriticalSection(FLock);
  18.     end;
  19.   end;
  20.  
  21. // Das oft verwendete FreeThenNil (zB. bei TCustomForm/TApplication) ist
  22. // auch nichts anderes als .Free: LCLProc.pas, 639ff:
  23. procedure FreeThenNil(var AnObject: TObject);
  24. begin
  25.   if AnObject<>nil then begin
  26.     AnObject.Free;
  27.     AnObject:=nil;
  28.   end;
  29. end;


MfG


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Sep 01, 2007 15:34 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
*hust* Ähm ok... Ich hab erstmal alle Destroy-Aufrufe in Free aufrufe umgeformt. Geändert hat es leider nichts. aber ich habe jetzt mal die Feherausgabe kopiert und stell sie mal hier rein:

Zitat:
An unhandled exception occurred at $7C81CB88 :
Exception : Unknown Run-Time error : 202
$7C81CB88 INSERT, line 1 of windows.pp
$7C81CC05 INSERT, line 1 of windows.pp
$7C81CC19 INSERT, line 1 of windows.pp
$00446EA1 DO_WRITE, line 76 of sysfile.inc
$00446066 FILEWRITEFUNC, line 36 of C:/lazarus/source/fpcbuild/2.0.4/fpcsrc/rtl/inc/text.inc
$00441C89 fpc_writeln_end, line 514 of C:/lazarus/source/fpcbuild/2.0.4/fpcsrc/rtl/inc/text.inc
$00439ADE TWORLDDEFINITIONMANAGER__DESTROY, line 1205 of worldManager.pas
$00442109 TOBJECT__FREE, line 115 of C:/lazarus/source/fpcbuild/2.0.4/fpcsrc/rtl/inc/objpas.inc
$0043A399 TWORLDMANAGER__DESTROY, line 1374 of worldManager.pas
$00442109 TOBJECT__FREE, line 115 of C:/lazarus/source/fpcbuild/2.0.4/fpcsrc/rtl/inc/objpas.inc
$00437DF7 TWORLDDEFINITIONDISPLAYABLEOBJECT__DESTROY, line 939 of worldManager.pas
$00442109 TOBJECT__FREE, line 115 of C:/lazarus/source/fpcbuild/2.0.4/fpcsrc/rtl/inc/objpas.inc
$00439E0E TWORLDDEFINITIONMANAGER__CLEARWARES, line 1289 of worldManager.pas

$00439EA4 TWORLDDEFINITIONMANAGER__CLEARALL, line 1305 of worldManager.pas
$00439AEA TWORLDDEFINITIONMANAGER__DESTROY, line 1207 of worldManager.pas
$00442109 TOBJECT__FREE, line 115 of C:/lazarus/source/fpcbuild/2.0.4/fpcsrc/rtl/inc/objpas.inc
$0043A399 TWORLDMANAGER__DESTROY, line 1374 of worldManager.pas


RunTimeError 202 ist laut Referenzen ein "Stack overflow". Sonst seh ich den immer nur bei zu vielen rekursiven aufrufen. Nun, das dürfte wohl daran liegen, dass Destroy immernoch x-mal aufgerufen wird...

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: Mi Sep 05, 2007 17:08 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Hi mal wieder...
Ich habe heute meinen Kopf gegen die Wand geschlagen

Erstmal habe ich noch ein weiteres Problem entdect: Aus (da noch mysteriösen) gründen, hat sich FDefinitions in TWorldManager auf nil gesetzt, als es ein TworldDefinitionObjectWare erstellt hat... Nun, das war schonmal sehr verwirrend... Ich hab aber jetzt die Ursache allen übels (und ja, ihr dürft lachen, und zwar schön laut)
Code:
  1.  
  2. // TworldDefinitionDisplayableObject ist eine Vorfahrenklasse von TworldDefinitionObjectWare
  3. constructor TworldDefinitionDisplayableObject.Create(AManager: TworldManager);
  4. begin
  5.   inherited Create(AManager);
  6.   FDisplayName := '';
  7.   FDescription := '';
  8.  
  9.   FConditions := TworldDefinitionConditionList(AManager); // BÖÖÖÖSE ZEILE!!!
  10.   FConditions.FParent := nil;
  11. end;  
  12.  


Nun, man sieht es. Interessanterweise ist die Position von FConditions.FParent gleich der von World.FDefinitions. Dadurch kam es zu dem Problem mit dem FDefinitions setzt sich selbst auf nil beim erstellen von TworldDefinitionObjectWare...
Dadurch, dass FConditions (welches ja nur der gecastete TworldManager war) natürlich freigegeben wurde kam es dann zur endlosschleife in den Destruktoren... Hachja...

So, und jetzt will ich hier so viele lachende Smilies sehen wie Firefox gleichzeitig in 2GB Arbeitsspeicher halten kann :mrgreen:

Tjaja, was so ein vergessenes .Create ausrichten kann...

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  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 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 ]