Specyfikatory wyjątków zostały wycofane, ponieważ specyfikatory wyjątków są generalnie okropnym pomysłem . noexceptzostał dodany, ponieważ jest to jedyne rozsądnie użyteczne użycie specyfikatora wyjątku: wiedza, kiedy funkcja nie zgłosi wyjątku. W ten sposób staje się wyborem binarnym: funkcje, które będą rzucać i funkcje, które nie będą rzucać.
noexceptzostał dodany zamiast po prostu usuwać wszystkie specyfikatory rzutów, z wyjątkiem tego, throw()że noexceptjest potężniejszy. noexceptmoże mieć parametr, który w czasie kompilacji zamienia się w wartość logiczną. Jeśli wartość logiczna jest prawdziwa, to noexceptkije. Jeśli boolean ma wartość false, to noexceptnie przykleja się i funkcja może rzucić.
Możesz więc zrobić coś takiego:
struct<typename T>
{
void CreateOtherClass() { T t{}; }
};
Czy CreateOtherClassrzuca wyjątki? Może, jeśli Tdomyślny konstruktor to potrafi. Jak powiemy? Lubię to:
struct<typename T>
{
void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; }
};
W ten sposób CreateOtherClass()zgłosi iff domyślny konstruktor danego typu. Rozwiązuje to jeden z głównych problemów ze specyfikatorami wyjątków: ich niezdolność do propagowania stosu wywołań.
Nie możesz tego zrobić throw().
noexceptmoże również powodować kontrole w czasie wykonywania. Główna różnica między nimi polega na tym, że łamanienoexceptpowoduje,std::terminatea łamaniethrowpowodujestd::unexpected. Również nieco inne zachowanie podczas rozwijania stosu w tych przypadkach.