Was ist der technische Grund, warum es als schlechte Praxis angesehen wird, das throw
Schlüsselwort C ++ in einer Funktionssignatur zu verwenden?
bool some_func() throw(myExc)
{
...
if (problem_occurred)
{
throw myExc("problem occurred");
}
...
}
noexcept
sich etwas?Antworten:
Nein, dies wird nicht als bewährte Methode angesehen. Im Gegenteil, es wird allgemein als schlechte Idee angesehen.
http://www.gotw.ca/publications/mill22.htm geht viel detaillierter auf das Warum ein, aber das Problem ist teilweise, dass der Compiler dies nicht erzwingen kann, so dass es zur Laufzeit überprüft werden muss, was normalerweise der Fall ist unerwünscht. Und es wird auf keinen Fall gut unterstützt. (MSVC ignoriert Ausnahmespezifikationen mit Ausnahme von throw (), die es als Garantie dafür interpretiert, dass keine Ausnahme ausgelöst wird.
quelle
Jalf ist bereits damit verbunden, aber das GOTW bringt es ganz gut auf den Punkt , warum Ausnahmespezifikationen nicht so nützlich sind, wie man hoffen könnte:
Das ist genau das, worauf es ankommt. Sie werden wahrscheinlich nur einen Anruf erhalten
terminate()
und Ihr Programm stirbt an einem schnellen, aber schmerzhaften Tod.Die Schlussfolgerung der GOTW lautet:
quelle
Um allen anderen Antworten auf diese Frage einen Mehrwert zu verleihen, sollte man einige Minuten in die Frage investieren: Was ist die Ausgabe des folgenden Codes?
Antwort: Wie hier erwähnt , wird das Programm
std::terminate()
aufgerufen und somit wird keiner der Ausnahmebehandler aufgerufen.Details: Die erste
my_unexpected()
Funktion wird aufgerufen, aber da sie am Ende keinen passenden Ausnahmetyp für denthrow_exception()
Funktionsprototyp erneut auslöst,std::terminate()
wird sie aufgerufen. Die vollständige Ausgabe sieht also folgendermaßen aus:quelle
Der einzige praktische Effekt des Wurfspezifizierers besteht darin
myExc
,std::unexpected
dass aufgerufen wird, wenn etwas anderes als von Ihrer Funktion ausgelöst wird (anstelle des normalen nicht behandelten Ausnahmemechanismus).Um die Art von Ausnahmen zu dokumentieren, die eine Funktion auslösen kann, gehe ich normalerweise folgendermaßen vor:
quelle
Als der Sprache Wurfspezifikationen hinzugefügt wurden, war dies mit den besten Absichten geschehen, aber die Praxis hat einen praktischeren Ansatz bestätigt.
In C ++ lautet meine allgemeine Faustregel, nur Wurfspezifikationen zu verwenden, um anzuzeigen, dass eine Methode nicht werfen kann. Dies ist eine starke Garantie. Ansonsten gehe davon aus, dass es alles werfen könnte.
quelle
Nun, während ich über diese Wurfspezifikation googelte, habe ich mir diesen Artikel angesehen: - ( http://blogs.msdn.com/b/larryosterman/archive/2006/03/22/558390.aspx )
Ich reproduziere auch hier einen Teil davon, damit er in Zukunft verwendet werden kann, unabhängig davon, ob der obige Link funktioniert oder nicht.
Wenn der Compiler dies mit dem Attribut "throw ()" sieht, kann der Compiler die Variable "bar" vollständig optimieren, da er weiß, dass eine Ausnahme von MethodThatCannotThrow () nicht ausgelöst werden kann. Ohne das Attribut throw () muss der Compiler die Variable "bar" erstellen. Wenn MethodThatCannotThrow eine Ausnahme auslöst, kann / wird der Ausnahmebehandler vom Wert der Balkenvariablen abhängen.
Darüber hinaus können (und werden) Quellcode-Analysetools wie prefast die Funktion throw () verwenden, um ihre Fehlererkennungsfunktionen zu verbessern. Wenn Sie beispielsweise einen Versuch / Fang ausführen und alle von Ihnen aufgerufenen Funktionen als throw () markiert sind, Sie brauchen das try / catch nicht (ja, dies hat ein Problem, wenn Sie später eine Funktion aufrufen, die auslösen könnte).
quelle
Eine No-Throw-Spezifikation für eine Inline-Funktion, die nur eine Mitgliedsvariable zurückgibt und möglicherweise keine Ausnahmen auslösen kann, kann von einigen Compilern verwendet werden, um Pessimierungen durchzuführen (ein erfundenes Wort für das Gegenteil von Optimierungen), die sich nachteilig auf die Leistung auswirken können. Dies ist in der Boost-Literatur beschrieben: Ausnahmespezifikation
Bei einigen Compilern kann eine No-Throw-Spezifikation für Nicht-Inline-Funktionen von Vorteil sein, wenn die richtigen Optimierungen vorgenommen werden und die Verwendung dieser Funktion die Leistung in einer Weise beeinflusst, die dies rechtfertigt.
Für mich klingt es so, als ob die Verwendung ein Aufruf eines sehr kritischen Auges im Rahmen einer Leistungsoptimierung ist, möglicherweise mithilfe von Profiling-Tools.
Ein Zitat aus dem obigen Link für diejenigen, die es eilig haben (enthält ein Beispiel für schlechte unbeabsichtigte Auswirkungen der Angabe eines Wurfs auf eine Inline-Funktion eines naiven Compilers):
quelle