Einzelnen Beitrag anzeigen

Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.337 Beiträge
 
Delphi 11 Alexandria
 
#1

Schutzblöcke überflüssig!?

  Alt 30. Sep 2020, 13:39
Mal eine ketzerische Behauptung...
Ich möchte das ganz gern mal diskutieren, weil ich immer wieder auf Schutzblöcke stoße, die ich für unnötig halte...
Vermutlich stehe ich da wieder ziemlich allein, aber der Sinn von generellen Schutzblöcken um alle erzeugten Objekte erschließt sich mir einfach nicht...
Ich halte Schutzblöcke im Allgemeinen für völlig überflüssig, außer dort, wo bestimmte Fehler ausdrücklich erwartbar sind:


Folgender Code wird niemals einen Fehler produzieren:
Delphi-Quellcode:
obj1 := nil;
obj2 := nil;
obj3 := nil;

Beep;

obj1 := TObject.Create;
obj2 := TObject.Create;
obj3 := TObject.Create;

Beep;

obj1.Free;
obj2.Free;
obj3.Free;
Wenn doch, liegt das an irgendeinem Hardwareproblem oder Compilerfehler, der von der eigenen Software nicht beeinflussbar ist.
Insofern ist es völlig unsinnig, die Objektfreigaben in einen finally-Abschnitt zu packen.

Der Code wird viel länger und unübersichtlicher und es gibt überhaupt keinen wirklichen Nutzen.

Bei mehreren verschachtelten Schutzblöcken wird es immer unübersichtlicher.


Delphi-Quellcode:
obj1 := nil;
obj2 := nil;
obj3 := nil;

try
  Beep;

  obj1 := TObject.Create;
  obj2 := TObject.Create;
  obj3 := TObject.Create;
  try
    Beep;
  except
    // Exception handling
  end;
finally
  obj1.Free;
  obj2.Free;
  obj3.Free;
end;
Die Ausstattung des Codes mit Schutzblöcken erzeugt also mehr Aufwand und verringert die Übersichtlichkeit.

Während der gesamten Laufzeit der Anwendung wird das Programm mit 99,99999%iger Sicherheit an diesen Stellen niemals eine Exception werfen.

Die Schutzblöcke sind hier also völlig überflüssig.


Natürlich gibt es auch Fälle, wo Schutzblöcke etwas nachvollziehbarer sind.

Wenn wir jetzt in dem Code statt Beep eine Funktion DivHundretBy(X: Integer)aufrufen und dort verschiedene Werte DivHundretBy(Random(10)) übergeben, erhalten wir irgendwann bei den Tests den Laufzeitfehler "Division durch Null".

Während der Programmentwicklung ist es erst mal egal, dass die zuvor erzeugten Objekte beim Stopp der Anwendung nicht freigegeben wurden.
Das ist absolut unerheblich.

Wir werden den Fehler nun bereinigen. Je nach Bedarf wird ausgeschlossen, dass die Funktion mit 0 ausgerufen wird DivHundretBy(Random(9)+1) oder es gibt eine andere Behandlung dieses Sonderfalles.

Danach können wir wieder sehr sicher sein, dass die Berechnung fehlerfrei (ohne werfen einer Exception) funktionieren wird und der Finally-Abschnitt ist wieder verzichtbar. Wir werden so oder so niemals eine Exception erhalten und die Objekte werden immer korrekt freigegeben und die berechneten Werte stimmen (Programm arbeitet fehlerfrei).


Wenn man während der Projektentwicklung solch eine Problemstelle übersehen hat und der Endanwender eine Exception-Meldung erhält, muss der Fehler natürlich schnellstmöglich bereinigt werden.
Ob die 3 o.g. Objekte in dem Moment freigegeben werden oder nicht, ist nebensächlich.
Das wäre nur interessant, wenn im Sekundentakt tausende neue Speicherlecks entstehen und aufgeräumt werden müssten.
Im Grunde kann der Anwender mit dem Programm so oder so erst mal nicht mehr sinnvoll arbeiten, weil man erst mal nicht einschätzen kann, ob der Datenbestand überhaupt noch konsistent ist oder nicht.

Hier steht halt dringend eine Fehlerbereinigung aus, aber ob die 3 Objekte nun noch freigegeben wurden oder nicht, spielt keine wirkliche Rolle.
Jedenfalls sehe ich den Aufwand, den Code dagegen mit try...finally um alle Objekterzeugungen und Freigaben zuzupflastern als völlig unverhältnismäßig an.

Da ist mir schlanker, funktionierender Code deutlich lieber.
Die Fehlerbereinigung muss identisch durchgeführt werden.



Natürlich gibt es auch Fälle, wo immer mit einem Problem gerechnet werden muss, dass man selbst nicht beeinflussen kann. Als Beispiel gäbe es da Erzeugen von Ordnern, Netzwerkunterbrechungen, Zugriffsfehler auf Dateien o.ä.
In den Fällen macht es natürlich schon Sinn, mit Schutzblöcken zu arbeiten und z.B. Speicherbereiche direkt wieder frei zu geben.
Das sehe ich dann aber als "geplanten Ablauf der Anwendung" an. Es gehört halt zu Anwendung dazu, dass z.B. ein Ordner nicht erstellt werden kann oder eine Verbindung unterbrochen wird. Wenn man das Problem nicht zuvor selbst auschließen kann (wie z.B. bei einer Division durch Null), dann kann man zumindest auf den Problemfall gezielt reagieren und einen Programmablauf vorsehen.


Aber Schutzblöcke generell um Objekterzeugungen halte ich in den allermeisten Fällen für unnötig.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat