Thema: Delphi Frage zu FreeAndNil

Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#23

Re: Frage zu FreeAndNil

  Alt 27. Feb 2010, 23:56
Ja.

Pragmatisch betrachtet kann es immer vorkommen das die Childrens über deren Parent auf die anderen Childrens zugreifen wollen, zu jedem Zeitpunkt. Das in meinem Beispiel die Objektfelder .Left und .Right auch nil sein können ist ein gezieltes Designkriterium, da sowas in einem Baum eben der Fall ist. Ergo: benutzt man den Status "nil" auch als Information.
Tödlich wird es in diesem Beispiel gerade dann wenn diese Objektreferenzen bei Freigabe der Objekte nicht sauber und sicher freigegeben werden. Das geht nur mit FreeAndNil() oder vergleichbaren Verfahren.

Die Freigabe eines Childs in solchen Bäumen ist zu jedem Zeitpunkt möglich, wenn man Informationen in den Baum hinzufügt, wegnimmt, umsortiert, merged, komprimiert oder eben den Baum komplett freigibt. Der Zustand NIL ist also ein Normalfall in diesem Beispiel.

Da es um jeden beliebigen Zeitpunkt geht ist eine Notification wie in deinem Vorschlag eben keine Lösung, diese Notification bezieht sich nur auf den Fall der Freigabe des Baumes und nicht prinzipiell zu jedem Lebenszyklus oder Operation des Baumes. Zudem würde die Struktur dieses Baumes damit verletzt. Denn nun müssten ja alle Childrens eines Baumes sich merken das die anderen Childrens zerstört wurden oder das sich der Baum in der Zerstörung befindet. Das ist wesentlich fehleranfällirer am Ende, als ein einfacher FreeAndNil() Aufruf und dem gezielten Ausnutzen das eben diese Objektreferenzen im Parent auch nil sein könnten.

Der schlimmste Designfehler meiner Meinung nach ist es ein sich gestelltes Ziel nicht mit dem geringst möglichen Aufwand sauber lösen zu wollen, sondern der Versuch durch Verkompilizierung es nur schön zu machen. Wenn das Mittel "nil setzen einer Objektrefernz" vorhanden ist und wenn es das Mittel mit dem geringsten Aufwand ist dann sollte man es nutzen.

Zitat:
bei dem von dir beschriebenen Szenario stört mich, dass die Kind-Objekte in ihrem Destruktor(!) auf eventuell bereits zerstörte Geschwister-Objekte zugreifen. Dies ließe sich meiner Meinung nach verhindern, wenn das Eltern-Objekt die Freigabe über einen Aufruf "Child.Destroying" ankündigen würde.
Naja oder noch einfacher, im Destruktor der Childs wird einfach nicht mehr auf die Objektstruktur des Baumes zugegriffen

Allerdings führte ich in meiner obigen Argumentation mit Bedacht auch die Möglichkeit der Windows Botschaftsbearbeitung, als asynchrones und nicht vorhersagbares Element, mit auf. Denn exakt solche Gegebenheiten existieren in der Praxis und dann sollte der Programmierer auch dies berücksichtigen. Der Programmier kann in diesem Moment eben nicht planmäßig davon ausgehen das selbst im Destruktor des Parents, durch untergeordnete Childs und deren Windows Botschaften, solche Zugriffe nicht stattfinden werden.

Notifications helfen da wenig und verkomplizieren dann nur alles. Zudem die Notificaions selber wiederum anfällig wären, denn auch diese sind auf gültige Objektrefernezen angewiesen. Und eine gültige Objektreferenz bezeichnet auch den Fall = nil.

In Bezug auf solche Bäume kommt es auch häufig vor das man Objektrefernezen tauschen muß, zb. bei der Umsortierung. Auch dort sollte man die gleiche Technik wie in FreeAndNil() verwenden um es sauber zu machen. Defakto wird man es auch so machen und damit ist FreeAndNil() nur ein Spezialfall unter vielen anderen.

Anders ausgedrückt: bei meinem Beispiel ist das FreeAndNil() im Destruktor nur eine kritische Operation unter anderen. Sie unterscheidet sich in keinster Weise von zb. dem Einfügen oder Entfernen neuer Objekte in den Baum. Ergo, mein Beispiel zeigt das die Beschränkung der Diskussion auf den Destruktor und FreeAndNil() im Vergleich zu einfachem .Free, eine sinnfreie Argumention sein wird um Designfehler zu bewerten. Im Gegenteil, mein Beipiel zeigt ein mögliches Design auf in dem es ein Designfehler wäre eben nicht FreeAndNil() zu benutzen. Selbst Notifications wären ungeeignet und eine zu überkompensierte Lösung des Problemes die die Fehleranfälligkeit noch inkrementieren würde, eben ebenfalls ein Designfehler.

Nun, wenn ich dieses Gegenbeispiel anführen kann, dann ist es fakt das die eigentliche Diskussion sinnfrei wird, da sich eben keine Generalisierung davon ableiten lässt, es existieren ja die Bäume zb. Und was mich eben stört ist die Aussage: FreeAndNil() nicht im Destruktor zu verwenden da man so eventuelle Designfehler vertuschen würde. Das abgleitete Indiz das nach Änderung vom .Free auf FreeAndNil() nun keine fehler mehr auftreten würden halte ich für unwahrscheinlich. Im Allgemeinen kann es sich ja nur auf illegale Speichzugriffe auf nicht mehr existente Speicherobjekte beziehen. Wurde die Referenz mit FreeAndNil() bereinigt dann treten diese AVs weiterhin auf, aber dieses Mal eben beim Zugriff auf Addresse 0x0000??. Der Designfehler wäre also nicht vertuscht nur eventuell dessen Wahrscheinlichkeit der Entdeckung reduziert. Und ob es überhaupt ein Designfehler ist sei dahin gestellt, vielleicht fehlte ja nur eine Assigned() Anfrage in anderen Programmteilen die mit FreeAndNil() das Problem sauber gelösst hätte.

Und wie ichs schon sagte: das Problem sollte beseitigt werden und nicht nur die Symptome. Wenn also ein Programmierer mit FreeAndnil() das Symptom beseitigt dann ist das eher ein Indiz für Schlampigkeit in der Arbeitsweise statt ein Hinweis auf einen Designfehler. Die gemachte Ableitung der Eingangsdiskussion ist also falsch.

Gruß Hagen
  Mit Zitat antworten Zitat