Vor mehr als 10 Jahren haben sie Ihnen beigebracht, Ausnahmespezifizierer zu verwenden. Da ich einer der torvaldischen C-Programmierer bin, der C ++ hartnäckig meidet, wenn ich nicht dazu gezwungen werde, lande ich nur sporadisch in C ++.
Die Mehrheit der C ++ - Programmierer scheint sich jedoch über Ausnahmespezifizierer hinwegzusetzen. Ich habe die Debatte und die Argumente von verschiedenen C ++ - Gurus wie diesen gelesen . Soweit ich es verstehe, läuft es auf drei Dinge hinaus:
- Ausnahmespezifizierer verwenden ein Typsystem, das nicht mit dem Rest der Sprache übereinstimmt ("Schattentypsystem").
- Wenn Ihre Funktion mit einem Ausnahmespezifizierer etwas anderes auslöst als das, was Sie angegeben haben, wird das Programm auf unerwartete Weise abgebrochen.
- Ausnahmespezifizierer werden im kommenden C ++ - Standard entfernt.
Vermisse ich hier etwas oder sind das alle Gründe?
Meine eigenen Meinungen:
Zu 1): Na und? C ++ ist in Bezug auf die Syntax wahrscheinlich die inkonsistenteste Programmiersprache, die jemals erstellt wurde. Wir haben die Makros, die goto / labels, die Horde (hoard?) Von undefiniertem / nicht spezifiziertem / implementierungsdefiniertem Verhalten, die schlecht definierten Integer-Typen, alle impliziten Regeln für die Typwerbung, Schlüsselwörter in Sonderfällen wie friend, auto , registrieren, explizit ... und so weiter. Jemand könnte wahrscheinlich mehrere dicke Bücher von all der Verrücktheit in C / C ++ schreiben. Warum reagieren die Menschen also auf diese besondere Inkonsistenz, die im Vergleich zu vielen anderen weitaus gefährlicheren Merkmalen der Sprache ein kleinerer Fehler ist?
Zu 2): Ist das nicht meine eigene Verantwortung? Es gibt so viele andere Möglichkeiten, wie ich einen fatalen Fehler in C ++ schreiben kann. Warum ist dieser spezielle Fall noch schlimmer? Anstatt throw(int)
Crash_t zu schreiben und dann zu werfen, kann ich auch behaupten, dass meine Funktion einen Zeiger auf int zurückgibt, dann eine wilde, explizite Typumwandlung durchführt und einen Zeiger auf einen Crash_t zurückgibt. Der Geist von C / C ++ war es immer, den größten Teil der Verantwortung dem Programmierer zu überlassen.
Was ist dann mit Vorteilen? Am offensichtlichsten ist, dass der Compiler einen Fehler ausgibt, wenn Ihre Funktion versucht, einen anderen als den von Ihnen angegebenen Typ explizit auszulösen. Ich glaube, dass der Standard diesbezüglich klar ist (?). Fehler treten nur auf, wenn Ihre Funktion andere Funktionen aufruft, die wiederum den falschen Typ auslösen.
Aus einer Welt deterministischer, eingebetteter C-Programme kommend, würde ich mit Sicherheit lieber genau wissen, was eine Funktion auf mich wirft. Wenn es etwas in der Sprache gibt, das das unterstützt, warum nicht? Die Alternativen scheinen zu sein:
void func() throw(Egg_t);
und
void func(); // This function throws an Egg_t
Ich denke, es besteht eine große Chance, dass der Anrufer den Try-Catch im zweiten Fall ignoriert / vergisst, weniger im ersten Fall.
Soweit ich weiß, stürzt das Programm ab, wenn eine dieser beiden Formen plötzlich eine andere Art von Ausnahme auslöst. Im ersten Fall, weil es nicht erlaubt ist, eine weitere Ausnahme auszulösen, im zweiten Fall, weil niemand damit gerechnet hat, dass ein SpanishInquisition_t ausgelöst wird und daher dieser Ausdruck nicht dort abgefangen wird, wo er hätte sein sollen.
Im letzteren Fall scheint es nicht wirklich besser zu sein, als einen Programmabsturz (...) auf der höchsten Ebene des Programms zu haben: "Hey, irgendwo in Ihrem Programm hat etwas eine seltsame, unbehandelte Ausnahme ausgelöst ". Sie können das Programm nicht wiederherstellen, wenn Sie so weit von der Stelle entfernt sind, an der die Ausnahme ausgelöst wurde. Sie können lediglich das Programm beenden.
Und aus der Sicht des Benutzers ist es ihnen egal, ob sie vom Betriebssystem ein böses Meldungsfeld mit der Aufschrift "Programm beendet. Blablabla bei Adresse 0x12345" oder ein böses Meldungsfeld von Ihrem Programm mit der Aufschrift "Unbehandelte Ausnahme: myclass" erhalten. func.something ". Der Bug ist immer noch da.
Mit dem kommenden C ++ - Standard habe ich keine andere Möglichkeit, als auf Ausnahmespezifizierer zu verzichten. Aber ich würde lieber ein solides Argument hören, warum sie schlecht sind, als "Seine Heiligkeit hat es gesagt und so ist es". Vielleicht gibt es mehr Argumente gegen sie als die, die ich aufgelistet habe, oder vielleicht steckt mehr dahinter, als mir klar wird?
Antworten:
Ausnahmebedingungsspezifikationen sind schlecht, weil sie schwach durchgesetzt werden und daher nicht viel bewirken. Sie sind auch schlecht, weil sie die Laufzeit auf unerwartete Ausnahmen prüfen lassen, damit sie terminate () ausführen können, anstatt UB aufzurufen Dies kann eine erhebliche Menge an Leistung verschwenden.
Zusammenfassend lässt sich sagen, dass Ausnahmespezifikationen in der Sprache nicht stark genug erzwungen werden, um den Code tatsächlich sicherer zu machen, und dass die Implementierung wie angegeben einen großen Leistungsverlust darstellte.
quelle
Ein Grund, warum niemand sie benutzt, ist, dass Ihre Hauptannahme falsch ist:
Dieses Programm kompiliert ohne Fehler oder Warnungen .
Darüber hinaus wird das Programm beendet , obwohl die Ausnahme abgefangen worden wäre .
Edit: ein Punkt in Ihrer Frage zu beantworten, catch (...) (oder besser, catch (std :: exeption &) oder eine andere Basisklasse, und dann fangen (...)) ist sinnvoll , noch , auch wenn Sie dies nicht tun weiß genau was schief gelaufen ist.
Bedenken Sie, dass Ihr Benutzer eine Menüschaltfläche für "Speichern" gedrückt hat. Der Handler für die Menüschaltfläche lädt die Anwendung zum Speichern ein. Dies könnte aus unzähligen Gründen fehlschlagen: Die Datei befand sich in einer verschwundenen Netzwerkressource, es gab eine schreibgeschützte Datei und sie konnte nicht überschrieben werden usw. Dem Handler ist es jedoch egal, warum etwas fehlgeschlagen ist. Es ist nur wichtig, dass es entweder erfolgreich war oder fehlgeschlagen ist. Wenn es gelungen ist, ist alles gut. Wenn es fehlgeschlagen ist, kann es dem Benutzer mitteilen. Die genaue Art der Ausnahme ist unerheblich. Wenn Sie richtigen, ausnahmesicheren Code schreiben, bedeutet dies außerdem, dass sich ein solcher Fehler in Ihrem System ausbreiten kann, ohne dass er heruntergefahren wird - selbst bei Code, der den Fehler nicht berücksichtigt. Dies erleichtert die Erweiterung des Systems. Beispielsweise speichern Sie jetzt über eine Datenbankverbindung.
quelle
Dieses Interview mit Anders Hejlsberg ist ziemlich berühmt. Darin erklärt er, warum das C # -Designteam überprüfte Ausnahmen überhaupt verworfen hat. Kurz gesagt, es gibt zwei Hauptgründe: Versions- und Skalierbarkeit.
Ich weiß, dass sich das OP auf C ++ konzentriert, während Hejlsberg C # diskutiert, aber die Punkte, die Hejlsberg hervorhebt, sind auch perfekt auf C ++ anwendbar.
quelle