Freigeben über


Gewusst wie: Entwurf zur Ausnahmesicherheit

Einer der Vorteile von Ausnahmemechanismus ist die Ausführung, zusammen mit Daten über die Ausnahme, Sprünge direkt von der Anweisung, die die Ausnahme zur ersten catch-Anweisung auslöst, die es Handles.Der Handler kann eine beliebige Anzahl von Ebenen oben in der Aufrufliste.Funktionen, die zwischen der Versuchanweisung und der throw-Anweisung aufgerufen werden, sind erforderlich, um keine Informationen über die Ausnahme zu wissen, die ausgelöst wird.Sie müssen jedoch darauf geachtet werden, dass sie den Gültigkeitsbereich an jedem Punkt "unerwartet" verlassen können, in dem eine Ausnahme möglicherweise von oben unter weitergäbe, und erfolgen, ohne hinter teilweise erstellten Objekten, Speicherverlust oder Datenstrukturen zu belassen, die in den unbrauchbaren Zustand sind.

Grundlegende Techniken

Eine robuste Ausnahmebehandlungsrichtlinie erfordert umsichtigen Anmerkungen und sollte Teil des Designprozesses sein.Im Allgemeinen werden die meisten Ausnahmen an den Grundanstrichen eines Software-Moduls erkannt und ausgelöst, aber in der Regel haben diese Ebenen nicht genügend Kontext, um den Fehler zu behandeln oder einer Meldung Endbenutzer verfügbar zu machen.In den mittleren Ebenen können Funktionen eine Ausnahme abfangen und erneut auslösen, wenn sie das Ausnahmeobjekt überprüfen müssen oder sie die zusätzlichen nützlichen Informationen verfügen, der für die Oberschicht bereitzustellen, die letztendlich die Ausnahme abzufangen.Eine Funktion sollte abfangen und eine Ausnahme "schlucken" nur wenn es in der Lage ist, davon vollständig zu beheben.In vielen Fällen ist das richtige Verhalten in den mittleren Ebenen, eine Ausnahme in der Aufrufliste weitergegeben werden.Selbst auf der höchsten Ebene, empfiehlt es sich möglicherweise, eine nicht behandelte Ausnahme ein Programm beendet wird, wenn die Ausnahme das Programm in einem Zustand befindet, in dem die zugehörigen Korrektheit nicht garantiert werden kann.

Unabhängig davon eine Funktion eine Ausnahme behandelt, um zu helfen, sicherzustellen, dass es "ausnahmesich ist, muss sie entsprechend den folgenden grundlegenden Regeln entworfen.

Hh279653.collapse_all(de-de,VS.110).gifHalten Sie Ressourcen-Klassen einfach

Wenn Sie manuelle Ressourcenverwaltung in Klassen kapseln, verwenden Sie eine Klasse, die nichts anderes vornimmt, jede Ressource zu verwalten; andernfalls könnten Sie Verluste vor.

Hh279653.collapse_all(de-de,VS.110).gifVerwenden Sie das RAII-Idiom, um Ressourcen zu verwalten

Um ausnahmesich sind, muss eine Funktion sicherzustellen dass Objekte die sie zugeordnet sind oder indem sie mallocnew verwendeten zerstört werden, und alle Ressourcen wie Dateihandles freigegeben werden geschlossen oder wenn eine Ausnahme ausgelöst wird.Das Ausdrucksweise Resource Acquisition Is Initialization (RAII) bindet Verwaltung solcher Ressourcen an die Lebensdauer des automatischen Variablen.Wenn eine Funktion den Gültigkeitsbereich, entweder verlässt, indem sie normalerweise oder aufgrund einer Ausnahme zurückgibt, werden die Destruktoren für alle voll-erstellten automatischen Variablen aufgerufen.Ein RAII-Wrapperobjekt wie ein intelligenter Zeiger ruft die entsprechende Löschungs- oder Abschlussfunktion in ihrem Destruktor auf.Im ausnahmesicheren Code ist es kritisch wichtig, Eigentümer jeder Ressource auf jede Art von RAII-Objekt sofort zu übergeben.Beachten Sie, dass vector, string, make_shared, fstream und ähnliche Klassen Datenerfassung der Ressource für Sie behandeln. Allerdings sind unique_ptr und herkömmliche shared_ptr Konstruktionen speziell, da Ressourcendatenerfassung vom Benutzer anstelle des Objekts ausgeführt wird; daher zählen, da sie Ressourcen-Version Zerstörung ist, jedoch sind als RAII entsprechenden.

Die drei Ausnahme-Garantien

In der Regel wird Ausnahmesicherheit im Hinblick auf die drei Ausnahmegarantien erläutert, die eine Funktion bereitstellen kann: die NO- FAIL-Garantie, die starke Garantie und die grundlegende Garantie.

Hh279653.collapse_all(de-de,VS.110).gifNO-FAIL-Garantie

Die Garantie NO-FAILs (oder ", NO-THROW") ist die stärkste garantiert, die eine Funktion benötigen.Sie gibt an, dass die Funktion keine Ausnahme auslöst oder einem ermöglicht, weitergegeben.Sie können jedoch eine solche garantiert nicht zuverlässig bereitstellen, es sei denn, () Sie wissen, dass alle Funktionen, dass dieses Funktionsaufrufe auch NO-FAIL sind oder (b) Sie wissen, dass alle Ausnahmen, die ausgelöst werden, bevor sie diese Funktion erreichen oder (c) Sie können alle Ausnahmen abfangen und behandeln ordnungsgemäß abgefangen werden, die diese Funktion eingegeben haben.

basieren die starke Garantie und die grundlegende Garantie auf der Annahme, dass die Destruktoren NO-FAIL sind.Alle Container und Typen in die Standardbibliotheksgarantie ein, die ihre Destruktoren nicht auslösen.Es gibt auch eine gegenteilige Anforderung: Die Standardbibliothek erfordert die benutzerdefinierte Typen, die es-für beispielsweise angegeben werden, da Vorlage das nicht-Auslösen von Destruktoren verfügen Argument-muss.

Hh279653.collapse_all(de-de,VS.110).gifStarke Garantie

Die starken Garantiezustände, die, wenn eine Funktion im Bereich aufgrund einer Ausnahme verlässt, es nicht Arbeitsspeicher- und Programmzustände verloren gehen, werden nicht geändert.Eine Funktion, die eine starke Garantie bereitstellt, ist im Grunde eine Transaktion, die Commit- oder Rollbacksemantik verfügt: Methode wie folgt vollständig, oder hat keine Auswirkungen.

Hh279653.collapse_all(de-de,VS.110).gifGrundlegende Garantie

Die grundlegende Garantie ist der drei das schwächste.Es ist jedoch möglicherweise die beste Wahl, wenn eine starke Garantie im Speicherverbrauch oder in der Leistung zu aufwändig ist.Die grundlegenden Garantiezustände, die, wenn eine Ausnahme auftritt, kein Arbeitsspeicher Verlust wird und das Objekt ist noch in einem verwendbaren Zustand, obwohl die Daten möglicherweise geändert.

Ausnahmesiche Klassen

Eine Klasse kann helfen, seine eigene Ausnahmesicherheit sicherzustellen, auch wenn sie über unsichere Funktionen genutzt, indem sich verhindert, dass teilweise erstellt oder teilweise zerstört wird.Nach Beendigung eines Klassenkonstruktors vor Abschluss, dann das Objekt nie erstellt und ihr Destruktor wird nie aufgerufen.Obwohl die automatische Variablen, die vor der Ausnahme initialisiert werden, ihre aufgerufenen Destruktoren besitzen, belegte Speicher dynamisch oder Ressourcen, die nicht durch einen intelligenten Zeiger oder eine ähnliche automatische Variable verwaltet werden, werden verloren geht.

Die integrierten Typen sind alle NO-FAIL, und die Standardbibliothekstypen unterstützen die grundlegende Garantie an einem Minimum.Beachten Sie folgende Richtlinien für jeden benutzerdefinierten Typ, der ausnahmesich sein muss:

  • Verwenden Sie intelligenten Zeiger oder andere RAII-Typwrapper, um alle Ressourcen zu verwalten.Vermeiden Sie Ressourcenverwaltungsfunktionalität im Klassendestruktor, da der Destruktor nicht aufgerufen wird, wenn der Konstruktor eine Ausnahme auslöst.Wenn die Klasse ein dedizierter Ressourcen-Manager ist, der nur eine Ressource steuert, ist es zulässig, den Destruktor zu verwenden, um Ressourcen zu verwalten.

  • Erfahren Sie, dass eine Ausnahme, die in einen Basisklassenkonstruktor ausgelöst wird, nicht in einem abgeleiteten Klasse geschluckt werden kann.Wenn Sie die Basisklassenausnahme in einem abgeleiteten Konstruktor übersetzen und erneut auslösen möchten, verwenden Sie einen Funktionstry-block.Weitere Informationen finden Sie unter Gewusst wie: Behandeln von Ausnahmen in den Basisklassen-Konstruktoren (C++).

  • Überlegen Sie, ob alle Klassenzustand in einem Datenmember gespeichert werden, der in einem intelligenten Zeiger umschlossen wird, insbesondere wenn eine Klasse ein Konzept "der Initialisierung verfügt, die nicht zulässig ist, um fehl." Obwohl C++ nicht initialisierte Datenmember zulässt, unterstützt sie nicht die nicht initialisierten oder Teilinitialisierung Klasseninstanzen.Ein Konstruktor muss erfolgreich abgeschlossen oder fehlgeschlagen; kein Objekt wird erstellt, wenn der Konstruktor nicht vollständig ausgeführt wird.

  • Lassen Sie keine Ausnahmen für Escapezeichen über einen Destruktor.Ein grundlegendes Axiom von C++ ist, dass Destruktoren einer Ausnahme niemals ermöglichen sollten, um die Aufrufliste weitergegeben.Wenn ein Destruktor Vorgang möglicherweise Ausnahme-auslösen ausführen muss, muss er in einem Versuchcatch-block dazu und die Ausnahme schlucken.Die Standardbibliothek stellt diese Garantie auf allen Destruktoren bereit, die sie definiert.

Siehe auch

Konzepte

Fehler und Ausnahmebehandlung modernes (C++)

Gewusst wie: Schnittstelle zwischen Ausnahmem und Nicht-Ausnahmem Code