Warum ist C++0x `s " noexcept` dynamisch geprüft?
Ich bin neugierig, die Gründe für noexcept
im C++0x-FCD. throw(X)
war veraltet, aber noexcept
scheint das gleiche zu tun. Gibt es einen Grund, dass noexcept
nicht geprüft werden bei der Kompilierung? Es scheint, dass es besser wäre, wenn diese Funktionen wurden geprüft und statisch, dass Sie nur aufgerufen, werfen die Funktionen eine try
block.
- Auch, Seite 1107 hat eine schöne Fußnote, dass ist ziemlich lustig.
- Ha ha!!! Schön finden. Das ist so gut, wie die Neudefinition von "ill-formed" Programm "ein Möchtegern C++ - Programm, das nicht wohlgeformt" in N3035.
- Das problem mit der überprüfung dieser statisch ist, dass 1) es kann nicht wirklich robust, und 2) selbst wenn das geschehen war, es wäre immer noch ein großer Schmerz, mit zu arbeiten -- Zeugen die Probleme mit dem Java-Pendant. Niemand wirklich will, statisch geprüft, Ausnahme Bezeichner in C++. Die Frage ist mehr, ob die Ausnahme Planern sollte es auf alle
- Tatsächlich, das problem mit den lustigen Fußnoten ist, dass es macht es leicht zu verwechseln mit einem echten Fußnote für eine lustige ein, z.B., "342) Unter den sonstigen Auswirkungen, atomic-Variablen sind nicht verfallen."
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn ich mich werfen, ist veraltet, weil es keine Möglichkeit gibt, geben Sie alle Ausnahmen, die eine template-Funktion werfen kann. Auch für nicht-template-Funktionen benötigen Sie die throw-Klausel, weil Sie Hinzugefügt haben einige Spuren.
Auf der anderen Seite kann der compiler optimieren von code, der keine exceptions werfen. Siehe "Die Debatte über noexcept, Teil I" (zusammen mit teilen II und III) für eine ausführliche Diskussion. Der wichtigste Punkt scheint zu sein:
Im Grunde ist es eine linker problem, das standards committee war nur ungern zu brechen, ABI. (Wenn es nach mir geht, würde ich das tun, was es verlangt, ist die Bibliothek kompiliert wird, haben wir diese situation schon mit thread-Aktivierung, und es ist machbar.)
Überlegen, wie es funktionieren würde. Nehmen wir an, die Anforderungen waren
noexcept(true)
noexcept(true)
noexcept(false)
sofern nicht anders angegebennoexcept(true)
muss die Funktion wickeln Sie alle Ihrenoexcept(false)
Anrufe intry{}catch(...){}
Klingt vernünftig, richtig?
Um dies zu implementieren, der linker muss unterscheiden zwischen
noexcept(true)
undnoexcept(false)
Versionen von Funktionen, viel, wie Sie können overload const und const-Versionen der member-Funktionen.Also, was bedeutet das für Namen-namgling? Werden rückwärts-kompatibel mit bestehenden Objekt-code, den wir verlangen würden, dass alle vorhandenen Namen interpretiert als
noexcept(false)
mit extra mangeln für dienoexcept(true)
Versionen.Dies würde bedeuten wir können nicht link gegen bestehende Destruktoren, es sei denn, der header wird geändert, um sich Tags wie
noexcept(false)
Sprach ich zu standards Committee-Mitglied in person über diese und er sagt, dass dies war, stürzte Entscheidung, motiviert vor allem durch eine Einschränkung bei move-Operationen im Container (die Sie sonst vielleicht am Ende mit fehlenden Elementen nach einem zu werfen, das verstößt gegen die grundlegende Garantie). Wohlgemerkt, dies ist ein Mann, dessen erklärte design-Philosophie ist, dass fault-intolerant-code ist gut. Zeichnen Sie Ihre eigenen Schlussfolgerungen.
Wie gesagt, ich würde gebrochen haben das ABI in der Präferenz für das brechen der Sprache.
noexcept
ist nur eine marginale Verbesserung auf die alte Weise. Statische Kontrolle ist immer besser.extern "C"
Funktion, und bei einigen Implementierungen können Sie dies tun, auch wenn es heißt durch C-code, lassen die Ausnahme zu propagieren, zurück zu C++ - code, der weiß, wie man damit umgeht. Die exception-handling-Modell, die von GCC und Clang wird ausdrücklich ein design, das zu unterstützen, und Solaris unterstützt es auch. Dies ist gut definiert und nützlich. Ohne C-Funktionen als implizit nicht-werfen statischen überprüfung von exception-Spezifikationen wird nicht funktionieren. So dass wir nicht statisch überprüfen.noexcept(true)
zu C-Funktionen verursachen würde nützlich sind, gemäß der Sprache, die Erweiterungen werden nicht-konforme. (Es wäre ähnlich, C11 mit erhöhten Anforderungen, das verhindert, dass threads, die als Erweiterung, anstatt Hinzugefügt explizite Unterstützung für threads.) Auch, Destruktoren werfen ist nicht immer ein Fehler, und ist in der Tat manchmal hilfreich.Beachten Sie, dass
noexcept
prüft, für die eine Ausnahme, die ausgelöst durch ein Versagendynamic_cast
undtypeid
angewendet, um einenull
Zeiger, die nur getan werden kann zur Laufzeit. Andere tests können in der Tat getan werden zur compile-Zeit.dynamic_cast
odertypeid
außerhalb einertry
block...Anderen Antworten gesagt haben, Aussagen wie
dynamic_cast
s kann möglicherweise zu werfen, Sie kann aber nur zur Laufzeit überprüft, damit der compiler kann nicht sagen, für bestimmte, zum Zeitpunkt der Kompilierung.Dies bedeutet, dass zur compile-Zeit der compiler kann entweder lassen Sie Sie gehen (ie. nicht compile-time check), warnen, ablehnen, oder geradezu (was nicht nützlich). Das lässt die Warnung, als die einzige vernünftige Sache für den compiler zu tun.
Aber das ist noch nicht wirklich nützlich - angenommen, Sie haben eine
dynamic_cast
die aus welchem Grund auch immer Sie wissen, wird nie scheitern und eine exception werfen, da das Programm ist so geschrieben. Der compiler wahrscheinlich weiß das nicht und wirft eine Warnung, das wird Geräusche, die wahrscheinlich wird nur deaktiviert werden, indem die Programmierer für nutzlos, dass der Punkt der Warnung.Einem ähnlichen Problem ist, wenn Sie eine Funktion, die nicht mit angegeben
noexcept
(ie. Ausnahmen auslösen kann), die Sie anrufen möchten aus viele Funktionen, einigenoexcept
, einige nicht. Sie kennen die Funktion wird nie werfen die Umstände genannt, die von dernoexcept
Funktionen, aber wieder der compiler nicht: mehr nutzlose Warnungen.Also gibt es keine sinnvolle Möglichkeit für den compiler zu erzwingen, das zur compile-Zeit. Dies ist eher in den Bereich der statischen Analyse, die in der Regel mehr wählerisch und werfen Warnungen für diese Art der Sache.
Betrachten eine Funktion
Können Sie statisch zu überprüfen, ob die richtigen? Sie müsste wissen, ob foo oder bar gehen, um exceptions werfen. Sie zwingen könnte, alle Funktionen Anrufe werden innerhalb eines try {} - block, so etwas wie dieses
Aber das ist falsch. Wir haben keine Möglichkeit zu wissen, dass foo und bar werden nur werfen, dass die Art der Ausnahme. Um sicherzustellen, dass wir etwas fangen würden wir brauchen, um zu verwenden,"...". Wenn Sie nichts fangen, was werden Sie tun mit Fehlern, die Sie fangen? Wenn ein unerwarteter Fehler entsteht hier das einzige, was zu tun ist, Abbruch des Programms. Aber das ist im Grunde das, was die Laufzeit-check standardmäßig tun.
Kurz gesagt, bietet genug details, um zu beweisen, dass eine gegebene Funktion wird nie werfen Sie das falsche Ausnahmen produzieren würde verbose code in Fällen, in denen der compiler kann nicht sicher sein, ob oder nicht die Funktion werfen, der falsche Typ. Die Nützlichkeit der statische Nachweis ist wohl nicht der Mühe Wert.
fun
wirft, wennfoo
undbar
habe das "auslösen könnte" Spezifikationen basiert auf was, die Sie auslösen könnte. Wenn Sie werfenExceptionType
Objektefun
ist in Ordnung. Wenn Sie werfenOtherExceptionType
Objektefun
ist nicht in Ordnung. Die Prototypen sind nicht ausreichend, um dies festzustellen.Gibt es einige überschneidungen in der Funktionalität von
noexcept
undthrow()
, aber Sie sind wirklich kommen aus entgegengesetzten Richtungen.throw()
wurde über die Richtigkeit, und sonst nichts: eine Methode zum festlegen des Verhaltens, wenn eine unerwartete Ausnahme ausgelöst wurde.Ist der primäre Zweck der
noexcept
ist die Optimierung: Es ermöglicht/fördert der compiler zu optimieren, um die Annahme, dass keine exceptions geworfen werden.Aber ja, in der Praxis, Sie sind nicht viel mehr als zwei verschiedene Namen für die gleiche Sache. Die Motivationen dahinter sind unterschiedlich.
noexcept
ist die Richtigkeit auch. Werfen bewegt, brechen die starke Garantie, die zuvor korrekten code (wie Sortier-algorithmen und container-Größe), so brauchen wirstd::move_if_noexcept
umschreiben alten generischen code in einer sicheren Weise. Natürlich das fehlen der statischen Prüfung macht Verhalten sich wieassert
eher alsconst
aber das ist der Preis für die Abwärtskompatibilität 🙁noexcept
(und gleichthrow()
) es ist also nicht nur über compiler-Optimierungen, aber auch Auswirkungen auf die Bibliothek design und die Auswahl des Algorithmus. Der Schlüssel zu tun, dass ist dienoexcept
operator, der es erlaubt code-Abfrage, wie throwy ein Ausdruck ist, das an der neuen Sache, und alle, die interessiert, ist eine ja/Nein-Antwort, es ist nicht egal, welche Art von Ausnahme kann geworfen werden, nur ob man kann geworfen werden oder nicht