Namensräume
Varianten
Aktionen

Dynamische Ausnahmespezifikation (bis C++17)

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
Ausnahmen
try Block
Ausnahmen auslösen
Ausnahmen behandeln
Ausnahmespezifikation
    noexcept Spezifikation (C++11)
    dynamische Spezifikation (bis C++17*)
noexcept Operator (C++11)
 

Listet die Ausnahmen auf, die eine Funktion direkt oder indirekt auslösen kann.

Inhalt

[bearbeiten] Syntax

throw(type-id-list (optional)) (1) (in C++11 veraltet)
(removed in C++17)
1) Explizite dynamische Ausnahmespezifikation.
type-id-list - durch Kommas getrennte Liste von Type-IDs, ein Type-ID, das eine Pack-Erweiterung darstellt, wird von einer Ellipse (...) gefolgt(seit C++11)

Eine explizite dynamische Ausnahmespezifikation darf nur auf einem Funktionsdeklarator für einen Funktionaltyp, einen Zeiger auf einen Funktionaltyp, eine Referenz auf einen Funktionaltyp oder einen Zeiger auf eine Memberfunktionstyp erscheinen, der der oberste Typ einer Deklaration oder Definition ist, oder auf einem solchen Typ, der als Parameter- oder Rückgabetyp in einem Funktionsdeklarator erscheint.

void f() throw(int);            // OK: function declaration
void (*pf)() throw (int);       // OK: pointer to function declaration
void g(void pfa() throw(int));  // OK: pointer to function parameter declaration
typedef int (*pf)() throw(int); // Error: typedef declaration

[bearbeiten] Erklärung

Wenn eine Funktion mit einem Typ T deklariert wird, der in ihrer dynamischen Ausnahmespezifikation aufgeführt ist, kann die Funktion Ausnahmen dieses Typs oder eines davon abgeleiteten Typs auslösen.

Unvollständige Typen, Zeiger oder Referenzen auf unvollständige Typen außer cv void*, und Rvalue-Referenztypen(seit C++11) sind in der Ausnahmespezifikation nicht erlaubt. Array- und Funktionaltypen werden, falls sie verwendet werden, in entsprechende Zeigertypen umgewandelt; oberste cv-Qualifizierungen werden ebenfalls verworfen. Parameter-Packs sind erlaubt(seit C++11).

Eine dynamische Ausnahmespezifikation, deren Satz angepasster Typen leer ist (nachdem alle Packs erweitert wurden)(seit C++11), ist nicht-werfend. Eine Funktion mit einer nicht-werfenden dynamischen Ausnahmespezifikation erlaubt keine Ausnahmen.

Eine dynamische Ausnahmespezifikation gilt nicht als Teil des Typs einer Funktion.

Wenn die Funktion eine Ausnahme des Typs auslöst, der nicht in ihrer Ausnahmespezifikation aufgeführt ist, wird die Funktion std::unexpected aufgerufen. Die Standardfunktion ruft std::terminate auf, kann aber durch eine vom Benutzer bereitgestellte Funktion (über std::set_unexpected) ersetzt werden, die std::terminate aufrufen oder eine Ausnahme auslösen kann. Wenn die von std::unexpected ausgelöste Ausnahme von der Ausnahmespezifikation akzeptiert wird, wird die Stapelentwindung wie gewohnt fortgesetzt. Wenn nicht, aber std::bad_exception von der Ausnahmespezifikation zugelassen wird, wird std::bad_exception ausgelöst. Andernfalls wird std::terminate aufgerufen.

[bearbeiten] Instanziierung

Die dynamische Ausnahmespezifikation einer Funktionsschablonenspezialisierung wird nicht zusammen mit der Funktionsdeklaration instanziiert; sie wird nur instanziiert, wenn sie *benötigt* wird (wie unten definiert).

Die dynamische Ausnahmespezifikation einer implizit deklarierten speziellen Memberfunktion wird ebenfalls nur bei Bedarf ausgewertet (insbesondere erfordert die implizite Deklaration einer Memberfunktion einer abgeleiteten Klasse nicht, dass die Ausnahmespezifikation einer Basis-Memberfunktion instanziiert wird).

Wenn die dynamische Ausnahmespezifikation einer Funktionsschablonenspezialisierung *benötigt* wird, aber noch nicht instanziiert wurde, werden die abhängigen Namen gesucht und alle in einem Ausdruck verwendeten Schablonen so instanziiert, als ob es sich um die Deklaration der Spezialisierung handelt.

Eine dynamische Ausnahmespezifikation einer Funktion gilt in den folgenden Kontexten als *benötigt*:

  • in einem Ausdruck, wo die Funktion durch Überladungsauflösung ausgewählt wird
  • die Funktion wird ODR-verwendet
  • die Funktion würde ODR-verwendet, erscheint aber in einem nicht ausgewerteten Operand
template<class T>
T f() throw(std::array<char, sizeof(T)>);
 
int main()
{
    decltype(f<void>()) *p; // f unevaluated, but exception specification is needed
                            // error because instantiation of the exception specification
                            // calculates sizeof(void)
}
  • die Spezifikation wird benötigt, um sie mit einer anderen Funktionsdeklaration zu vergleichen (z. B. bei einem virtuellen Funktionsüberschreiber oder einer expliziten Spezialisierung einer Funktionsschablone)
  • in einer Funktionsdefinition
  • die Spezifikation wird benötigt, weil eine standardmäßig definierte spezielle Memberfunktion sie überprüfen muss, um ihre eigene Ausnahmespezifikation zu bestimmen (dies geschieht nur, wenn die Spezifikation der standardmäßig definierten speziellen Memberfunktion selbst benötigt wird).

[bearbeiten] Mögliche Ausnahmen

Jede Funktion f, jeder Zeiger auf eine Funktion pf und jeder Zeiger auf eine Memberfunktion pmf hat ein Set möglicher Ausnahmen, das aus Typen besteht, die ausgelöst werden können. Ein Set aller Typen bedeutet, dass jede Ausnahme ausgelöst werden kann. Dieses Set ist wie folgt definiert:

1) Wenn die Deklaration von f, pf oder pmf eine dynamische Ausnahmespezifikation verwendet, die nicht alle Ausnahmen zulässt(bis C++11), besteht das Set aus den in dieser Spezifikation aufgeführten Typen.
2) Andernfalls, wenn die Deklaration von f, pf oder pmf noexcept(true) verwendet, ist das Set leer.
(seit C++11)
3) Andernfalls ist das Set das Set aller Typen.

Hinweis: Für implizit deklarierte spezielle Memberfunktionen (Konstruktoren, Zuweisungsoperatoren und Destruktoren) und für die erbenden Konstruktoren(seit C++11) ist das Set möglicher Ausnahmen eine Kombination aus den Sets der möglichen Ausnahmen von allem, was sie aufrufen: Konstruktoren/Zuweisungsoperatoren/Destruktoren von nicht-varianten nicht-statischen Datenmitgliedern, direkten Basen und, wo angebracht, virtuellen Basen (einschließlich Standardargumentausdrücken, wie immer).

Jeder Ausdruck e hat ein Set möglicher Ausnahmen. Das Set ist leer, wenn e ein Kernkonstantausdruck ist, andernfalls ist es die Vereinigung der Sets möglicher Ausnahmen aller unmittelbaren Unterausdrücke von e (einschließlich Standardargumentausdrücken), kombiniert mit einem weiteren Set, das von der Form von e abhängt, wie folgt:

1) Wenn e ein Funktionsaufrufausdruck ist, sei g die aufgerufene Funktion, der Funktionszeiger oder der Zeiger auf eine Memberfunktion, dann:
  • wenn die Deklaration von g eine dynamische Ausnahmespezifikation verwendet, wird das Set möglicher Ausnahmen von g zum Set hinzugefügt;
  • wenn die Deklaration von g noexcept(true) verwendet, ist das Set leer;
(seit C++11)
  • andernfalls ist das Set das Set aller Typen.
2) Wenn e eine Funktion implizit aufruft (es ist ein Operator-Ausdruck und der Operator ist überladen, es ist ein new-Ausdruck und die Allokationsfunktion ist überladen, oder es ist ein vollständiger Ausdruck und der Destruktor eines Temporären wird aufgerufen), dann ist das Set das Set dieser Funktion.
3) Wenn e ein throw-Ausdruck ist, ist das Set die Ausnahme, die durch seinen Operanden initialisiert würde, oder das Set aller Typen für den erneut werfenden throw-Ausdruck (ohne Operand).
4) Wenn e ein dynamic_cast zu einer Referenz auf einen polymorphen Typ ist, besteht das Set aus std::bad_cast.
5) Wenn e ein typeid ist, das auf einen dereferenzierten Zeiger auf einen polymorphen Typ angewendet wird, besteht das Set aus std::bad_typeid.
6) Wenn e ein new-Ausdruck mit einer nicht-konstanten Array-Größe ist und die ausgewählte Allokationsfunktion ein nicht-leeres Set möglicher Ausnahmen hat, besteht das Set aus std::bad_array_new_length.
(seit C++11)
void f() throw(int); // f()'s set is "int"
void g();            // g()'s set is the set of all types
 
struct A { A(); };                  // "new A"'s set is the set of all types
struct B { B() noexcept; };         // "B()"'s set is empty
struct D() { D() throw (double); }; // new D's set is the set of all types

Alle implizit deklarierten Memberfunktionen und erbenden Konstruktoren(seit C++11) haben Ausnahmespezifikationen, die wie folgt ausgewählt werden:

  • Wenn das Set möglicher Ausnahmen das Set aller Typen ist, erlaubt die implizite Ausnahmespezifikation alle Ausnahmen (die Ausnahmespezifikation gilt als vorhanden, obwohl sie im Code nicht ausgedrückt werden kann und sich so verhält, als ob keine Ausnahmespezifikation vorhanden wäre)ist noexcept(false)(bis C++11)ist noexcept(false)(seit C++11).
  • Andernfalls, wenn das Set möglicher Ausnahmen nicht leer ist, listet die implizite Ausnahmespezifikation jeden Typ aus dem Set auf.
  • Andernfalls ist die implizite Ausnahmespezifikation throw()(bis C++11)noexcept(true)(seit C++11).
struct A
{
    A(int = (A(5), 0)) noexcept;
    A(const A&) throw();
    A(A&&) throw();
    ~A() throw(X);
};
 
struct B
{
    B() throw();
    B(const B&) = default; // exception specification is "noexcept(true)"
    B(B&&, int = (throw Y(), 0)) noexcept;
    ~B() throw(Y);
};
 
int n = 7;
struct D : public A, public B
{
    // May throw an exception of a type that would match a handler of type
    // std​::​bad_array_new_length, but does not throw a bad allocation exception
    (void*) new (std::nothrow) int[n];
 
    // D may have the following implicitly-declared members:
    // D::D() throw(X, std::bad_array_new_length);
    // D::D(const D&) noexcept(true);
    // D::D(D&&) throw(Y);
    // D::~D() throw(X, Y);
};

[bearbeiten] Hinweise

Clang betrachtet die Regel der Instanziierung von dynamischen Ausnahmespezifikationen in C++11 durch CWG1330 geändert, siehe LLVM #56349.

[bearbeiten] Schlüsselwörter

throw

[bearbeiten] Beispiel

Hinweis: Am besten in C++98-Modus kompilieren, um Warnungen zu vermeiden. Inkompatibel mit C++17 und neueren Revisionen.

#include <cstdlib>
#include <exception>
#include <iostream>
 
class X {};
class Y {};
class Z : public X {};
class W {};
 
void f() throw(X, Y) 
{
    bool n = false;
 
    if (n)
        throw X(); // OK, would call std::terminate()
    if (n)
        throw Z(); // also OK
 
    throw W(); // will call std::unexpected()
}
 
void handler()
{
    std::cerr << "That was unexpected!\n"; // flush needed
    std::abort();
}
 
int main()
{
    std::set_unexpected(handler);
    f();
}

Ausgabe

That was unexpected!

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 25 C++98 Das Verhalten von Zuweisung und Initialisierung
zwischen Zeigern auf Member mit unterschiedlichen
Ausnahmespezifikationen war undefiniert
Beschränkung anwenden
für Funktionszeiger
und Referenzen
CWG 973 C++98 Ausnahmespezifikation kann Funktionstypen enthalten, aber die
entsprechende Funktionszeigerkonvertierung wurde nicht spezifiziert
spezifiziert
CWG 1330 C++98 eine Ausnahmespezifikation könnte eifrig instanziiert werden sie wird nur instanziiert, wenn sie benötigt wird
CWG 1267 C++11 Rvalue-Referenztypen waren in Ausnahmespezifikationen erlaubt nicht erlaubt
CWG 1351 C++98
C++11
Standardargument (C++98) und Standard-Member-Initialisierer
(C++11) wurden in der impliziten Ausnahmespezifikation ignoriert
wurden berücksichtigt
CWG 1777 C++11 throw(T...) war keine nicht-werfende
Spezifikation, auch wenn T ein leeres Pack ist
sie ist nicht-werfend
wenn das Pack leer ist
CWG 2191 C++98 das Set möglicher Ausnahmen eines typeid-Ausdrucks
könnte bad_typeid enthalten, auch wenn es nicht ausgelöst werden kann
enthält bad_typeid
nur, wenn es ausgelöst werden kann

[bearbeiten] Siehe auch

noexcept Spezifikator(C++11) spezifiziert, ob eine Funktion Ausnahmen werfen kann[bearbeiten]