Спецификаторы исключений устарели, потому что спецификаторы исключений, как правило, ужасная идея . noexceptбыл добавлен, потому что это единственное разумно полезное использование спецификатора исключения: знание того, когда функция не генерирует исключение. Таким образом, это становится двоичным выбором: функции, которые будут вызывать и функции, которые не будут выбрасывать.
noexceptбыл добавлен вместо того, чтобы просто удалить все спецификаторы выброса, кроме того, throw()что noexceptон более мощный. noexceptможет иметь параметр, который во время компиляции преобразуется в логическое значение. Если логическое значение истинно, то noexceptприлипает. Если логическое значение false, то noexceptфункция не прилипает и функция может выбросить.
Таким образом, вы можете сделать что-то вроде этого:
struct<typename T>
{
void CreateOtherClass() { T t{}; }
};
Выбрасывает CreateOtherClassисключения? Может, если Tконструктор по умолчанию может. Как мы узнаем? Как это:
struct<typename T>
{
void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; }
};
Таким образом, CreateOtherClass()будет сгенерировано, если конструктор по умолчанию данного типа выбрасывает. Это устраняет одну из основных проблем со спецификаторами исключений: их неспособность распространяться вверх по стеку вызовов.
Вы не можете этого сделать с throw().
noexceptможет потребоваться проверка во время выполнения. Основное различие между ними в том , что ломаяnoexceptпричиныstd::terminate, разбиваяthrowпричиныstd::unexpected. Также в этих случаях немного другое поведение при раскручивании стека.