nachdem ich mein Projekt stets im Debug-Modus compiliere, dort pingelig darauf achte, jede Warnung zu verhindern und auch die Hints auf das absolute Mindestmaß zu reduzieren, alle Checks eingeschaltet lasse und auch den heaptrc eingeschaltet habe um frühzeitig Speicherleckagen zu entdecken, war ich entspannt, als ich den Schalter auf "Release" setzte.
Leider hat schlug meine Entspannung schnell um, denn das Programm, welches bisher reibungslos lief, hing einfach fest.
Durch geduldiges Suchen und Probieren, konnte ich jetzt das Problem eingrenzen, aber leider nicht in ein kleines Beispielprogramm auslagern. Meine Versuche, dieses Problem mit diesem Fehler an anderer Stelle nachzubauen, schlugen allesamt fehl.
Die eigentliche Fehlerstelle ist sehr übersichtlich.
Es gibt auch zwei Lösungen, die das Problem umschiffen, die auch sehr übersichtlich sind, aber ich würde gerne verstehen, was da schief geht, um zukünftig mögliche (weitere) Fehler zu umgehen.
Es handelt sich um eine Funktion des schon in anderen Beiträgen erwähnten Quadratur-Baums.
An dieser Stelle geht es darum, durch alle Knoten des Baums zu laufen und in jedem Knoten eine Variable auf 0 zu setzen.
Im Prinzip sieht das an dieser Stelle wie eine verkette Liste aus, die Funktion NextNode holt immer den dem übergebenen Knoten nachfolgenden Knoten und liefert den zurück:
Code: Alles auswählen
var
qn : TLazQuadNode;
begin
qn := FRootNode; // weise den Wurzelknoten der lokalen Variablen zu, der Wurzelknoten ist immer <> Nil
repeat
qn.FTotalNodeItemsCount := 0; // Setze die Variable im Knoten auf 0
qn := NextNode(qn); // Hole den nächsten Knoten
until not Assigned(qn); // wiederhole solange, bis kein weiterer Knoten mehr vorhanden ist
// Hier kommt weiterer Code
end;
Durch Debuggen, kann ich zeigen, dass die Funktion NextNode(qn) das richtige Ergebnis liefert, allein, das Funktionsergenis wird nicht der Variablen qn zugewiesen.
Somit arbeitet die Schleife immer auf dem gleichen Knoten.
Ich habe dann den Code etwas verändert, mit dem Ziel diese "Nichtzuweisung" beweisen zu können.
Code: Alles auswählen
var
qn, nn : TLazQuadNode;
begin
qn := FRootNode; // weise den Wurzelknoten der lokalen Variablen zu, der Wurzelknoten ist immer <> Nil
repeat
qn.FTotalNodeItemsCount := 0; // Setze die Variable im Knoten auf 0
nn := qn; // Merke den aktuellen Knoten
qn := NextNode(qn); // Hole den nächsten Knoten
if qn = nn then // wenn aktueller Knoten gleich alter Knoten
raise Exception.Create('Warum???'); // Erzeuge eine Exception
until not Assigned(qn); // wiederhole solange, bis kein weiterer Knoten mehr vorhanden ist
// Hier kommt weiterer Code
end;
Als Versuch Nummer 3 habe ich dann die Schleife nochmal anders aufgebaut.
Die Funktion NextNode kann nämlich auch mit dem Parameter Nil aufgerufen werden, sie liefert dann den FRootNode zurück.
Dies ausnutzend, habe ich die Schleife so aufgebaut, dass zu erst NextNode aufgerufen wird, dann (nach Prüfung auf Nil) die Zuweisung auf die Variable erfolgt.
Code: Alles auswählen
var
qn : TLazQuadNode;
begin
qn := Nil;
repeat
qn := NextNode(qn); // Hole den nächsten Knoten
if Assigned(qn) then // Wenn nicht Nil
qn.FTotalNodeItemsCount := 0; // Setze die Variable im Knoten auf 0
until not Assigned(qn); // wiederhole solange, bis kein weiterer Knoten mehr vorhanden ist
// Hier kommt weiterer Code
end;
Die Funktion rufe ich testweise direkt von einem Button auf. Versuchsweise habe ich innerhalb der Antwort-Methode des Button unmittelbar vor dem Aufruf der Funktion, die Schleife 1:1 abgebildet:
Code: Alles auswählen
var
// lTmpFN : String;
qn : TLazQuadNode;
begin
// Schleife exakt wie in der Methode RecountTotalNodeItems
qn := FTestQuadTree.RootNode;
repeat
qn.FTotalNodeItemsCount := 0;
qn := FTestQuadTree.NextNode(qn);
until not Assigned(qn);
FTestQuadTree.RecountTotalNodeItems; // Aufruf der Methode
end;
Was veranlasst den Compiler, den ersten Aufbau anders zu behandeln als nachfolgenden?
Ich habe Lazarus 4.3 mit FPC 3.2.2 am Start. Um sicher zu gehen, dass ich nicht irgendwelche alten Geister jage, habe ich die letzte Installation geladen und neuinstalliert und auch "alles aufräumen und compilieren" verwendet.
Über Hinweise wäre ich dankbar.