Mir wurde einmal geraten, dass ein C ++ - Programm letztendlich alle Ausnahmen abfangen sollte. Die Begründung lautete zu der Zeit im Wesentlichen, dass Programme, die es erlauben, dass Ausnahmen außerhalb main()
eines seltsamen Zombie-Zustands auftauchen . Dies wurde mir vor einigen Jahren mitgeteilt, und im Nachhinein glaube ich, dass das beobachtete Phänomen auf die langwierige Erzeugung außergewöhnlich großer Core-Dumps aus dem fraglichen Projekt zurückzuführen war.
Das wirkte damals bizarr, aber überzeugend. Es war völlig unsinnig, dass C ++ Programmierer "bestraft", weil sie nicht alle Ausnahmen abfingen, aber die Beweise vor mir schienen dies zu untermauern. Für das fragliche Projekt schienen Programme, die nicht abgefangene Ausnahmen ausgelöst hatten, in einen seltsamen Zombie-Zustand überzugehen - oder, wie ich jetzt vermute, ein Prozess inmitten eines unerwünschten Core-Dumps ist ungewöhnlich schwer zu stoppen.
(Für alle, die sich fragen, warum dies zu dieser Zeit nicht offensichtlicher war: Das Projekt erzeugte eine große Menge an Ausgaben in mehreren Dateien aus mehreren Prozessen, die jede Art von aborted (core dumped)
Nachricht effektiv verdeckten , und in diesem speziellen Fall war die Post-Mortem-Untersuchung von Core-Dumps nicht möglich Es ist keine wichtige Debugging - Technik, daher wurde nicht viel über Core - Dumps nachgedacht. Probleme mit einem Programm hingen normalerweise nicht vom Zustand ab, der von einem langlebigen Programm im Laufe der Zeit aus vielen Ereignissen angesammelt wurde, sondern von den anfänglichen Eingaben in ein kurzlebiges Programm (< 1 Stunde), daher war es praktischer, ein Programm mit denselben Eingaben aus einem Debugbuild oder in einem Debugger erneut auszuführen, um weitere Informationen zu erhalten.)
Derzeit bin ich mir nicht sicher, ob es einen großen Vorteil oder Nachteil gibt, Ausnahmen nur zu fangen, um das Verlassen von Ausnahmen zu verhindern main()
.
Der kleine Vorteil, den ich mir vorstellen kann, main()
wenn ich zulasse, dass Ausnahmen in die Vergangenheit sprudeln, ist, dass das Ergebnis std::exception::what()
auf dem Terminal gedruckt wird (zumindest mit GCC-kompilierten Programmen unter Linux). Auf der anderen Seite ist dies trivial zu erreichen, indem stattdessen alle Ausnahmen abgefangen std::exception
und das Ergebnis gedruckt werden. std::exception::what()
Wenn es wünschenswert ist, eine Nachricht von einer Ausnahme zu drucken, die nicht von std::exception
dieser Ausnahme stammt, muss sie vor dem Verlassen abgefangen main()
werden, um gedruckt zu werden die Nachricht.
Der bescheidene Nachteil, den ich mir main()
vorstellen kann, um Ausnahmen zuzulassen, ist, dass unerwünschte Kerndumps erzeugt werden können. Bei einem Prozess, der viel Arbeitsspeicher benötigt, kann dies ziemlich ärgerlich sein, und für die Steuerung des Core-Dump-Verhaltens in einem Programm sind betriebssystemspezifische Funktionsaufrufe erforderlich. Wenn andererseits ein Core-Dump und ein Exit gewünscht werden, kann dies stattdessen jederzeit durch Aufrufen erreicht werden, std::abort()
und ein Exit ohne Core-Dump kann jederzeit durch Aufrufen erreicht werden std::exit()
.
Anekdotischerweise glaube ich nicht, dass ich jemals die Standardnachricht gesehen habe, die what(): ...
von einem weit verbreiteten Programm nach einem Absturz gedruckt wurde.
Was sind, wenn überhaupt, die starken Argumente dafür oder dagegen, dass C ++ - Ausnahmen in die Vergangenheit sprudeln main()
?
Bearbeiten: Auf dieser Website gibt es viele allgemeine Fragen zur Ausnahmebehandlung. Meine Frage bezieht sich speziell auf C ++ - Ausnahmen, die nicht behandelt werden können und es bis jetzt geschafft haben. main()
Vielleicht kann eine Fehlermeldung gedruckt werden, aber es handelt sich um einen Fehler, der sofort angezeigt wird.
quelle
Antworten:
Ein Problem beim Übergehenlassen von Ausnahmen nach main besteht darin, dass das Programm mit einem Aufruf endet, bei
std::terminate
dem standardmäßig aufgerufen wirdstd::abort
. Es ist nur die Implementierung definiert, die ausgeführt wird, wenn der Stapel vor dem Aufruf gelöscht wird,terminate
sodass Ihr Programm beendet werden kann, ohne einen einzelnen Destruktor aufzurufen! Wenn Sie eine Ressource haben, die wirklich durch einen Destruktor-Aufruf wiederhergestellt werden musste, sind Sie in der Klemme ...quelle
std::abort
nicht und somit fehlgeschlagene Behauptungen auch nicht. Es ist auch erwähnenswert, dass auf modernen Betriebssystemen das Betriebssystem selbst viele Ressourcen (Speicher, Dateihandles, ...) bereinigt, die an die Prozess-ID gebunden sind. Schließlich habe ich auch auf "Defense in Depth" hingewiesen: Es ist unzuverlässig zu erwarten, dass alle anderen Prozesse fehlerfrei sind und immer die Ressourcen freigeben, die sie erworben haben (Sitzungen, ordentliches Ende des Schreibens von Dateien, ...), für die Sie planen müssen it ...WM_POWERBROADCAST
Nachricht abhören . Dies funktioniert nur, wenn Ihr Computer batteriebetrieben ist (wenn Sie einen Laptop oder eine USV verwenden).Der Hauptgrund dafür, dass Ausnahmen nicht ignoriert werden,
main
besteht darin, dass Sie sonst die Kontrolle darüber verlieren, wie das Problem Ihren Benutzern gemeldet wird.Für ein Programm, das nicht für längere Zeit verwendet oder weit verbreitet werden soll, kann es akzeptabel sein, dass unerwartete Fehler gemeldet werden, wie auch immer das Betriebssystem dies beschließt (z. B. das Anzeigen eines Dialogfelds mit In-Your-Face-Fehlern unter Windows ).
Bei Programmen, die Sie verkaufen oder die von einer Organisation, die einen guten Ruf hat, der Öffentlichkeit zur Verfügung gestellt werden, ist es im Allgemeinen besser, auf eine nette Art und Weise zu melden, dass Sie auf ein unerwartetes Problem gestoßen sind, und zu versuchen, so viel wie möglich davon zu sparen Benutzerdaten wie möglich. Wenn Sie nicht einen halben Arbeitstag Ihres Benutzers verlieren und nicht unerwartet abstürzen, sondern nur halbwegs ordnungsgemäß herunterfahren, ist dies in der Regel viel besser für Ihren Unternehmensruf als die Alternative.
quelle
main()
viel mit dem Betriebssystem zu tun hat? Das Betriebssystem weiß möglicherweise nichts von C ++. Meine Vermutung war, dass es durch den Code bestimmt wird, den der Compiler irgendwo in das Programm einfügt.TL; DR : Was steht in der Spezifikation?
Ein technischer Umweg ...
Wenn eine Ausnahme ausgelöst wird und kein Handler dafür bereit ist:
std::terminate
wird aufgerufen, was standardmäßig abbrichtLetzteres kann bei sehr seltenen Fehlern hilfreich sein (da die Reproduktion zeitaufwändig ist).
Ob alle Ausnahmen erfasst werden sollen oder nicht, ist letztendlich eine Frage der Spezifikation:
Für jedes Produktionsprogramm sollte dies angegeben werden, und Sie sollten die Spezifikation befolgen (und möglicherweise argumentieren, dass es geändert werden soll).
Für schnell zusammengewürfelte Programme, die nur von Fachleuten (Ihnen, Ihren Teamkollegen) verwendet werden dürfen, ist beides in Ordnung. Ich empfehle, es abstürzen zu lassen und die Umgebung so einzurichten, dass ein Bericht erstellt wird, oder nicht, je nach Ihren Anforderungen.
quelle
Eine Ausnahme, die Sie abfangen, gibt Ihnen die Möglichkeit, eine nette Fehlermeldung auszudrucken oder sogar zu versuchen, den Fehler zu beheben (möglicherweise indem Sie die Anwendung einfach neu starten).
In C ++ enthält eine Ausnahme jedoch keine Informationen zum Programmstatus, als sie ausgelöst wurde. Wenn Sie es abfangen, werden alle derartigen Zustände vergessen, wohingegen, wenn Sie das Programm abstürzen lassen, der Zustand normalerweise noch vorhanden ist und aus dem Programm-Dump gelesen werden kann, was das Debuggen erleichtert.
Es ist also ein Kompromiss.
quelle
In dem Moment, in dem Sie wissen, dass Sie den Vorgang abbrechen müssen, rufen Sie
std::terminate
bereits an, um weiteren Schaden einzudämmen.Wenn Sie wissen, dass Sie sich sicher entspannen können, tun Sie dies stattdessen. Denken Sie daran, dass das Abwickeln des Stapels nicht garantiert ist, wenn eine Ausnahme niemals abgefangen wird.
Wenn Sie den Fehler sicherer melden / protokollieren können, als dies das System alleine tun wird, fahren Sie fort.
Aber seien Sie wirklich sicher, dass Sie die Sache dabei nicht versehentlich verschlimmern.
Es ist oft zu spät, um Daten zu speichern, wenn Sie einen nicht behebbaren Fehler feststellen. Dies hängt jedoch vom jeweiligen Fehler ab.
Wie auch immer, wenn Ihr Programm für eine schnelle Wiederherstellung geschrieben wurde, ist es möglicherweise die beste Möglichkeit, es zu beenden, auch wenn es nur ein normales Herunterfahren ist.
quelle
Die meiste Zeit ist es gut, anmutig zusammenzustoßen - aber es gibt Kompromisse. Manchmal ist es gut, wenn man abstürzt. Ich sollte erwähnen, dass ich hauptsächlich über das Debuggen im großen Stil nachdenke. Für ein einfaches Programm - obwohl dies immer noch nützlich sein mag - ist es bei weitem nicht so hilfreich wie für ein sehr komplexes Programm (oder die Interaktion mehrerer komplexer Programme).
Sie möchten nicht in der Öffentlichkeit abstürzen (obwohl dies wirklich unvermeidlich ist - Programme stürzen ab, und ein wirklich mathematisch überprüfbares, nicht abstürzendes Programm ist nicht das, worüber wir hier sprechen). Denken Sie an Bill Gates BSODing mitten in einer Demo - schlecht, oder? Trotzdem können wir versuchen herauszufinden, warum wir abgestürzt sind und nicht noch einmal auf die gleiche Weise.
Ich habe eine Funktion der Windows-Fehlerberichterstattung aktiviert, mit der bei nicht behandelten Ausnahmen lokale Absturzabbilder erstellt werden. Es wirkt Wunder, wenn Sie die Symboldateien haben, die mit Ihrem (abstürzenden) Build verbunden sind. Interessanterweise möchte ich, weil ich dieses Tool eingerichtet habe, mehr abstürzen - weil ich aus jedem Absturz lerne. Dann kann ich die Fehler beheben und weniger abstürzen.
Deshalb möchte ich, dass meine Programme ganz nach oben springen und abstürzen. In Zukunft möchte ich vielleicht alle meine Ausnahmen mit Würde essen - aber nicht, wenn ich sie für mich arbeiten lassen kann.
Weitere Informationen zu lokalen Absturzabbildern finden Sie hier: Sammeln von Abbildern im Benutzermodus
quelle
Wenn eine Ausnahme nach main () auftritt, stürzt Ihre Anwendung ab, und meiner Meinung nach sollte eine App niemals abstürzen. Wenn es in Ordnung ist, eine App an einem Ort zum Absturz zu bringen, warum dann nicht überall? Warum sich überhaupt mit der Ausnahmebehandlung beschäftigen? (Sarkasmus, was nicht wirklich darauf hindeutet ...)
Möglicherweise haben Sie eine globale Try / Catch-Funktion, die eine elegante Meldung ausgibt, die dem Benutzer mitteilt, dass ein nicht behebbarer Fehler aufgetreten ist und er eine E-Mail an Bob in der IT senden muss. Es ist trivial zu verhindern, und Sie können einen Benutzer darüber informieren, was gerade passiert ist und wie man Dinge behebt, damit es nicht wieder passiert.
Crashing ist eine reine Amateurstunde.
quelle
main
. Wenn Sie nicht wissen, wie Sie damit umgehen sollen, ist es offensichtlich ein wirklich schrecklicher Fehler, so zu tun, als ob Sie es tun.