Beim Betrachten eines Codes bin ich auf Folgendes gestoßen:
throw /*-->*/new std::exception ("//...
und ich dachte immer, dass du hier nicht brauchst / nicht verwenden solltest new
.
Was ist der richtige Weg, sind beide in Ordnung, wenn ja, gibt es einen Unterschied?
Übrigens, was ich beim "Greifen" mit PowerShell-Boost-Bibliotheken sehen kann, wird nie verwendet throw new
.
PS Ich habe auch einen CLI-Code gefunden, der verwendet throw gcnew
. Ist das in Ordnung?
throw gcnew
wäre nützlich zB. Wenn Sie möchten, dass verwalteter Code Ihre Ausnahme abfängt. Kann mich jemand korrigieren?System::Exception
ist im Allgemeinen ein Verweis auf ein verwaltetes Objekt auf dem Garbage Collected Heap. Ich habe immer mit geworfengcnew
und gefangen mitSystem::Exception ^
. Natürlich verwende ich diefinally
ganze Zeit auch in C ++ / CLI, obwohl ich nicht oft mit C ++ - Ausnahmen im selbentry
Block mische , bin ich mir nicht sicher warum.Antworten:
Die herkömmliche Methode zum Auslösen und Abfangen von Ausnahmen besteht darin, ein Ausnahmeobjekt auszulösen und es als Referenz (normalerweise als
const
Referenz) abzufangen. Die C ++ - Sprache erfordert, dass der Compiler den entsprechenden Code generiert, um das Ausnahmeobjekt zu erstellen und es zum richtigen Zeitpunkt ordnungsgemäß zu bereinigen.Es ist niemals eine gute Idee, einen Zeiger auf ein dynamisch zugewiesenes Objekt zu werfen. Ausnahmen sollen es Ihnen ermöglichen, angesichts von Fehlerbedingungen robusteren Code zu schreiben. Wenn Sie ein Ausnahmeobjekt auf herkömmliche Weise auslösen, können Sie sicher sein, dass es zum richtigen
catch (...)
Zeitpunkt korrekt zerstört wird , wenn es von einer catch-Klausel mit dem Namen des richtigen Typs abgefangen wird , ob es dann erneut ausgelöst wird oder nicht. (Die einzige Ausnahme ist, wenn es nie gefangen wird, aber dies ist eine nicht behebbare Situation, wie auch immer Sie es betrachten.)Wenn Sie einen Zeiger auf ein dynamisch zugewiesenes Objekt werfen, müssen Sie sicherstellen, dass unabhängig davon, wie der Aufrufstapel an dem Punkt aussieht, an dem Sie Ihre Ausnahme auslösen möchten, ein catch-Block vorhanden ist, der den richtigen Zeigertyp benennt und den entsprechenden
delete
Aufruf hat. Ihre Ausnahme darf niemals abgefangen werden, escatch (...)
sei denn, dieser Block löst die Ausnahme erneut aus, die dann von einem anderen catch-Block abgefangen wird, der die Ausnahme korrekt behandelt.Tatsächlich bedeutet dies, dass Sie die Ausnahmebehandlungsfunktion verwendet haben, die das Schreiben von robustem Code erleichtern und es sehr schwierig machen soll, Code zu schreiben, der in allen Situationen korrekt ist. Abgesehen von dem Problem, dass es fast unmöglich sein wird, als Bibliothekscode für Client-Code zu fungieren, der diese Funktion nicht erwartet.
quelle
Keine Notwendigkeit
new
beim Auslösen einer Ausnahme.Einfach schreiben:
und fangen als:
Beachten Sie, dass
yourexception
vonstd::exception
direkt oder indirekt abgeleitet werden sollte.quelle
new
? warum ableitenyourexception
vonstd::exception
?throw std::exception;
? g ++ scheint es nicht zu kompilieren ...std::exception
ist ein Typ, und Sie können keinen Typ werfen , Sie müssen ein Objekt werfen . Die Syntax sollte also so lauten:throw std::exception();
Das wird kompiliert. Wie gut das ist, ist eine ganz andere Frage.Das Werfen
new std::exception
ist korrekt, wenn die Anrufstelle erwartet, a zu fangenstd::exception*
. Aber niemand wird damit rechnen, einen Zeiger auf eine Ausnahme zu finden. Selbst wenn Sie dokumentieren, was Ihre Funktion tut, und die Leute die Dokumentation lesen, können sie dennoch vergessen und versuchen,std::exception
stattdessen einen Verweis auf ein Objekt zu finden.quelle
new std::exception
ist nur dann korrekt, wenn die aufrufende Site erwartet, einen Zeiger abzufangen UND die Verwaltung der Zuweisungsausnahme zu übernehmen UND es niemals Fälle geben wird, in denen Ihre Funktion von etwas aufgerufen wird, das nicht explizit abfängt den richtigen Zeiger (catch(...)
oder überhaupt keine Behandlung), sonst tritt ein Objektleck auf. Kurz gesagt, dies kann als "nie" angenähert werden.Die C ++ FAQ hat eine nette Diskussion dazu:
Grundsätzlich gilt: "Es sei denn, es gibt einen guten Grund, nicht nach Referenz zu fangen. Vermeiden Sie es, nach Wert zu fangen, da dadurch eine Kopie erstellt wird und die Kopie ein anderes Verhalten aufweisen kann als das, was geworfen wurde. Nur unter ganz besonderen Umständen sollten Sie mit dem Zeiger fangen." ""
quelle
A
vom Typ unterscheidet.A*
Wenn ich das tue,throw A()
kann ich NICHT damit fangen,catch(A* e)
da es sich um einen völlig anderen Typ handelt.Operator new kann nicht garantieren, dass niemals eine Ausnahme ausgelöst wird. Aus diesem Grund würde die Verwendung zum Auslösen einer "gültigen" (beabsichtigten) Ausnahme einen Code erzeugen, bei dem nicht garantiert werden kann, dass er nicht abstürzt. Da es möglicherweise immer nur eine Ausnahme gibt und Ihr Programm versucht, zwei auszulösen, bevor eine davon abgefangen werden kann, kann eine Implementierung Ihr Programm am besten sofort abbrechen, z. B. durch Aufrufen von std :: terminate.
quelle