Ich habe eine allgemeine Frage zu Best Practice in OO Delphi. Gegenwärtig stelle ich try-finally-Blöcke überall dort hin, wo ich ein Objekt erzeuge, um dieses Objekt nach der Benutzung freizugeben (um Speicherlecks zu vermeiden). Zum Beispiel:
%Vor%anstelle von:
%Vor%Glauben Sie, dass es eine gute Übung oder zu viel Aufwand ist? Und was ist mit der Leistung?
Meiner Meinung nach gibt es nur einen Grund, warum eine Objektkonstruktion nicht gefolgt werden sollte ( oder" in "wie Mason wies ) a try / finally
block.
Diese Verwaltung kann drei Formen annehmen:
Mit # 1 , wenn die Referenz einen größeren Bereich hat sollte die Referenz sofort auf Null gesetzt werden, wenn sie nicht sofort erstellt wird. Auf diese Weise, wenn es als Referenz überprüft wird, wissen Sie, dass Sie eine genaue Lesung haben. Dies ist am häufigsten bei Elementobjekten der Fall, die als Teil einer größeren Klasse erstellt und dann bereinigt werden, wenn das übergeordnete Objekt zerstört wird.
Mit # 2 , wenn ein Objekt zu einer Liste hinzugefügt wird möchten Sie nur einen try-except
-Block (eines der wenigen, die ich benutze) verwenden falls eine Ausnahme auftritt, nachdem das Objekt erstellt wurde und bevor es der Verwaltungsliste hinzugefügt wird. Idealerweise fügt die erste Zeile nach der Konstruktion sie der Liste hinzu, oder die Liste ist eigentlich eine Factory-Klasse, die Ihnen ein Objekt gibt, das bereits zur Liste hinzugefügt wurde.
Mit # 3 , wenn ein Objekt einen anderen Lifetime Manager hat , sollten Sie wirklich sicherstellen, dass die Verwaltung durch diesen Manager das Richtige ist. Wenn Sie ein VCL-Steuerelement erstellen, könnten Sie versucht sein, das Formular (oder ein anderes Steuerelement) zu besitzen, was jedoch zusätzlichen Aufwand für die Konstruktion und die Zerstörung bedeutet. Wenn möglich, sollten Sie es explizit freigeben, das gilt insbesondere, wenn Sie das Steuerelement einmal aktivieren, dann wissen Sie, dass Sie es im Destruktor Ihres Formulars freigeben oder wenn es geschlossen wird. Dies ist nur möglich, wenn die Erstellung der Steuerung dynamischer ist.
Also, es ist eine bewährte Methode, viele try / finally
Blöcke zu verwenden. Sie sollten nur ein paar try / except
-Blöcke haben, und die meisten von ihnen sollten sehr spezifische Ausnahme-Typen abfangen und / oder die Ausnahme erneut auslösen. Wenn Sie mehr try / except
als try / finally
Blöcke haben, dann machen Sie es falsch .
Es ist definitiv die beste Vorgehensweise, try-finally zu verwenden.
Wenn eine Ausnahme ausgelöst wird, wird das Objekt freigegeben .
Was die Leistung angeht: messen , bevor Sie optimieren.
Wie Frank sagte: "Was die Leistung angeht: messen Sie, bevor Sie optimieren." Wiederholen Sie es, um zu betonen.
Wenn Sie eine Gruppe von Objekten in einer Methode erstellen, müssen Sie auch keinen try..finally-Block für jede von ihnen verwenden. Das kann zu einem hässlichen Eindruck führen. create, try, create, try, create, try, do something, finally, free, finally, free, finally, free.
Ugh! Stattdessen können Sie die Objektreferenzen am Anfang der Methode auf nil setzen, dann alle erstellen, einen try-Block ausführen und sie alle im finally-Abschnitt freigeben.
Das spart Overhead und Leistung (obwohl Sie den Unterschied wahrscheinlich nie bemerken werden), aber was noch wichtiger ist, macht Ihren Code sauberer und einfacher zu lesen, während das Sicherheitsniveau beibehalten wird.
Um Teil zwei Ihrer Frage zu beantworten:
try finally
hat kaum einen Overhead.
Tatsächlich gibt es viele Methoden, die einen impliziten Versuch haben ... endlich zu blockieren. Zum Beispiel mit einer Funktion, die eine lokale Variable eines beliebigen Schnittstellentyps verwendet und einem Wert einen Wert zuweist.
- Jeroen
Letztes Jahr bei Delphi Developer Days habe ich Marco Cantus privaten Code-Vorrat gesehen und er versucht es jedes Mal, wenn er etwas kreiert.
Jemand hat ihn danach gefragt, und er sagte, er versuche es die ganze Zeit.
Aber es ist besonders eine gute Idee für Multi-Threaded-Code, wenn es darum geht, kritische Abschnitte zu betreten und zu verlassen, obwohl das nicht zum Thema ist, ist es eine gute Sache, sich daran zu erinnern.
Offensichtlich ist es manchmal ein bisschen aufdringlich und wenn es nicht in der Kultur Ihres Arbeitsumfelds ist, in Ihrer Robsutness genau zu sein, kann es Sie dazu bringen, wie ein Goodie-Two-Shoes auszusehen. Aber ich denke, es ist eine gute Idee. Es ist so ähnlich wie Delphis Versuch, manuelle Garbage Collection zu erzwingen.
Wenn Sie das Objekt im Konstruktor einer Klasse erstellen und das Objekt der einschließenden Klasse gehört, möchten Sie es im Destruktor der besitzenden Klasse freilassen.
Ich neige dazu, FreeAndNil () anstelle von Free zu verwenden.
EDIT: Aber wie andere schon gesagt haben, willst du definitiv immer das, was du erstellst, befreien.
Ja, es ist immer eine gute Idee (wichtig), wenn der Code, der das Objekt erstellt, dafür verantwortlich ist, es freizugeben. Wenn nicht, dann probiere / endlich ist es nicht angebracht, aber dann ist es auch wieder nicht .Frei auf jeden Fall!
Es kann jedoch mühsam sein, wenn dieser Standardcode Ihre "Geschäftslogik" hervorhebt, und Sie sollten vielleicht einen Ansatz in Betracht ziehen, der die gleiche Garantie hat, Ihre Objekte zu befreien, der aber viel sauberer ist (und andere Vorteile hat), wie meine eigene AutoFree () Implementierung .
Mit AutoFree () könnte dann Ihr Code geschrieben werden:
%Vor%oder alternativ, da die Implementierung einen Verweis auf eine Referenz verwendet (um Auto-NIL'ing sowie Free'ing zu aktivieren), können Sie sogar Ihre Referenzen vorregistrieren, für die Sie eine AutoFree-Funktion wünschen Housekeeping-Deklarationen weg von Ihrer Geschäftslogik und halten Sie das echte "Fleisch" Ihres Codes so sauber wie möglich (dies ist besonders vorteilhaft, wenn potenziell mehrere Objekte frei sein müssen):
%Vor%Nicht in meinem ursprünglichen Beitrag gezeigt ist eine spätere Ergänzung zu dem Mechanismus zur Unterstützung der Registrierung mehrerer Referenzen in einem einzigen AutoFree () -Aufruf, aber ich bin mir sicher, dass Sie die Änderungen herausfinden können, um dies selbst zu unterstützen, wenn Sie möchte dies tun können:
%Vor%Auch wenn es viel zu empfehlen ist, dies zu tun, werde ich es nicht immer tun.
Meine Regeln zur Verwendung oder Nichtbenutzung des try / finally:
Der einzige Ort, an dem es schwierig ist, eine Entscheidung zu treffen, ist, wenn Sie beim Erstellen des Objekts Tausende von Malen Leistung benötigen (z. B. in einer Schleife). In diesem Fall verwende ich try nicht, es sei denn, das Objekt führt einfache Aufgaben aus und es besteht eine geringe Chance, dass es abstürzt.
Tags und Links delphi try-finally