Ich habe an vielen Stellen schon andere Anweisungen verwendet, allerdings bin ich neu in der Ausnahmebehandlung. Was ist der Hauptunterschied zwischen diesen beiden ...
für zB:
%Vor%ODER
%Vor%Also verwenden wir hier Standardklasse für Ausnahme, die einige in build Funktion wie e.what hat. Es kann also ein Vorteil sein ... abgesehen davon, dass wir alle anderen Funktionen handhaben können, wenn auch sonst. Gibt es noch andere Vorteile bei der Verwendung der Ausnahmebehandlung?
danke
Um zu sammeln, was die Kommentare in einer Antwort sagen:
seit der Standardisierung 1998 gibt new
bei einem Fehler keinen Nullzeiger zurück, sondern löst eine Ausnahme aus, nämlich std::bad_alloc
. Dies unterscheidet sich von Cs malloc
und vielleicht von einigen frühen Vor-Standard-Implementierungen von C ++, wobei new
möglicherweise auch NULL zurückgegeben hat (ich weiß nicht, tbh).
Es gibt eine Möglichkeit in C ++, einen Nullzeiger bei einem Zuteilungsfehler anstatt einer Ausnahme zu erhalten:
%Vor% Kurz gesagt, der erste Code, den Sie haben, wird nicht wie beabsichtigt funktionieren, da es ein Versuch der C-style-Fehlerbehandlung in Gegenwart von C ++ - Ausnahmen ist. Wenn die Zuweisung fehlschlägt, wird die Ausnahme ausgelöst, der if-Block wird nie eingegeben und das Programm wird wahrscheinlich beendet, da Sie bad_alloc
nicht abfangen.
Es gibt viele Artikel, in denen die allgemeine Fehlerbehandlung mit Ausnahmen verglichen mit Rückgabecodes verglichen wird, und es würde viel zu weit gehen, um das Thema hier zu behandeln. Zu den Gründen für Ausnahmen gehören
errno
-Variable und einem einzelnen zurückgegebenen Fehlercode. Der Hauptunterschied besteht darin, dass die Version, die mindestens die Ausnahmebehandlung verwendet, funktionieren könnte, wobei die mit der if
-Anweisung möglicherweise nicht funktionieren kann.
Dein erstes Snippet:
%Vor% ... scheint davon auszugehen, dass new
im Falle eines Fehlers einen Nullzeiger zurückgibt. Während das zu einer Zeit wahr war, war es nicht in einer langen Zeit. Mit jedem einigermaßen aktuellen Compiler hat das new
nur zwei Möglichkeiten: Erfolg oder Wurf. Daher stimmt Ihre zweite Version damit überein, wie C ++ funktionieren soll.
Wenn Sie wirklich diesen Stil verwenden möchten, können Sie den Code so umschreiben, dass er im Falle eines Fehlers einen Nullzeiger zurückgibt:
%Vor% In den meisten Fällen sollten Sie new
sowieso nicht direkt verwenden - Sie sollten wirklich std::vector<int> p(1000);
verwenden und damit fertig sein.
Damit bin ich gezwungen, hinzuzufügen, dass es für eine Menge Code wahrscheinlich am sinnvollsten ist, beides nicht zu tun und einfach anzunehmen, dass die Speicherzuweisung erfolgreich sein wird.
Zu einer Zeit (MS-DOS) war es ziemlich üblich, dass die Speicherzuweisung fehlschlug, wenn Sie versuchten, mehr Speicher zuzuweisen als verfügbar war - aber das war lange her. Heutzutage sind die Dinge nicht so einfach (in der Regel). Aktuelle Systeme verwenden virtuellen Speicher, was die Situation viel komplizierter macht.
Unter Linux passiert normalerweise, dass selbst der Speicher nicht wirklich verfügbar ist. Linux wird das tun, was als "Overcommit" bezeichnet wird. Sie erhalten immer noch einen Nicht-Null-Zeiger, als ob die Zuweisung erfolgreich gewesen wäre - aber wenn Sie versuchen, den Speicher zu verwenden, werden schlimme Dinge passieren. Insbesondere hat Linux einen sogenannten "OOM-Killer", der im Grunde davon ausgeht, dass das Auslaufen von Arbeitsspeicher ein Zeichen für einen Fehler ist. Wenn dies geschieht, versucht es, die fehlerhaften Programme zu finden und tötet sie. Für den praktischsten Zweck bedeutet dies, dass Ihr Programm wahrscheinlich getötet wird, und andere (halb-willkürlich gewählte) auch sein können.
Windows bleibt dem Modell, das C ++ erwartet, etwas näher. Wenn also beispielsweise Ihr Code auf einem unbeaufsichtigten Server ausgeführt wird, schlägt die Zuweisung möglicherweise fehl. Lange bevor es jedoch scheitert, wird es den Rest der Maschine in die Knie zwingen und in einem verhängnisvollen Versuch, die Zuweisung erfolgreich zu machen, verrückt tauschen. Wenn der Benutzer den Computer zu dem Zeitpunkt tatsächlich betreibt, wird in der Regel entweder Ihr Programm beendet oder andere deaktiviert, um genügend Speicher für Ihren Code freizugeben, um den angeforderten Speicher relativ schnell zu erhalten.
In keinem dieser Fälle ist es besonders realistisch, gegen die Annahme zu programmieren, dass eine Zuteilung fehlschlagen kann. Für die meisten praktischen Zwecke passiert eines von zwei Dingen: Entweder ist die Zuweisung erfolgreich oder das Programm stirbt.
Das führt zurück zum vorherigen Hinweis: In einem typischen Fall sollten Sie in der Regel std::vector
verwenden und davon ausgehen, dass Ihre Zuweisung erfolgreich ist . Wenn Sie darüber hinaus Verfügbarkeit bereitstellen müssen, müssen Sie es einfach auf andere Weise tun (z. B. den Prozess neu starten, wenn er abbricht, vorzugsweise auf eine Weise, die weniger Arbeitsspeicher belegt).
Wie bereits erwähnt, würde Ihr ursprüngliches if-else-Beispiel immer noch eine Ausnahme ab C ++ 98 auslösen, obwohl das Hinzufügen von nothrow
(wie bearbeitet) es wie gewünscht funktionieren lassen sollte (return null
, also trigg if- Aussage).
Im Folgenden gehe ich vereinfachend davon aus, dass für if-else zur Behandlung von Ausnahmen Funktionen zurückgegeben werden, die bei einer Ausnahme den Wert false zurückgeben.
Einige Vorteile von Ausnahmen oben, wenn-sonst, aus dem Kopf:
Sie kennen den Typ der Ausnahme für Logging / Debugging / Bugfixing
Beispiel:
Wenn eine Funktion eine Ausnahme auslöst, können Sie in angemessenem Umfang feststellen, ob ein Problem mit dem Code vorliegt oder etwas, das Sie nicht wie eine Ausnahme wegen zu wenig Speicherplatz ausführen können.
Wenn das if-else eine Funktion zurückgibt, haben Sie keine Ahnung, was in dieser Funktion passiert ist.
Sie können natürlich eine separate Protokollierung verwenden, um diese Informationen aufzuzeichnen, aber warum nicht einfach eine Ausnahme mit den Ausnahmedetails zurückgeben, die stattdessen enthalten sind?
Sie müssen kein Chaos von if-else-Bedingungen haben, um die Ausnahme an die aufrufende Funktion weiterzugeben
Beispiel: (Kommentare enthalten, um Verhalten anzuzeigen)
%Vor%(Es gibt viele Leute, die nicht gerne Funktionen mit mehreren Return-Anweisungen haben. In diesem Fall haben Sie eine noch unordentlichere Funktion.)
Im Gegensatz zu:
%Vor%Eine Alternative zu oder Erweiterung von if-else sind Fehlercodes. Dafür bleibt der zweite Punkt erhalten. Siehe für mehr über den Vergleich zwischen diesen und Ausnahmen.
Wenn Sie den Fehler lokal behandeln, ist if ... else
sauberer. Wenn die Funktion, bei der der Fehler auftritt, den Fehler nicht behandelt, wird eine Ausnahme ausgelöst, die an eine höhere Person in der Aufrufkette weitergegeben wird.
Zunächst wird Ihr erster Code mit der if-Anweisung das Programm beenden, falls der neue Operator [] wegen einer nicht behandelten Ausnahme eine Ausnahme auslöst. Sie können dies beispielsweise hier überprüfen: Ссылка
Auch in vielen anderen Fällen werden Ausnahmen ausgelöst, nicht nur, wenn die Zuweisung fehlgeschlagen ist und ihr Hauptmerkmal (in meinen Augen) die Steuerung in der Anwendung nach oben verschiebt (an Stelle, wo die Ausnahme behandelt wird). Ich empfehle Ihnen, mehr über Ausnahmen zu lesen, gutes Lesen wäre "Effektiveres C ++" von Scott Meyers, es gibt ein großes Kapitel über Ausnahmen.
Tags und Links c++ exception-handling if-statement