Не используйте спецификации исключений
Причина
Спецификации исключений делают обработку ошибок хрупкой, налагают накладные расходы во время выполнения и были удалены из стандарта C++.
Пример
int use(int arg)
throw(X, Y)
{
// ...
auto x = f(arg);
// ...
}
Если f() бросает исключение, отличное от X и Y, вызывается обработчик unexpected, который по умолчанию завершает программу. Это нормально, но скажем, мы проверили, что это не может произойти, и f изменяется, чтобы бросать новое исключение Z — теперь у нас аварийное завершение, если мы не изменим use() (и не перетестируем всё). Загвоздка в том, что f() может находиться в библиотеке, которую мы не контролируем, и новое исключение — это нечто, с чем use() ничего не может поделать или в чём оно никоим образом не заинтересовано. Мы можем изменить use() для передачи Z дальше, но теперь, вероятно, нужно изменить вызывающих use(). Это быстро становится неуправляемым. Альтернативно, мы можем добавить try-catch в use() для преобразования Z в приемлемое исключение. Это тоже быстро становится неуправляемым. Заметьте, что изменения в наборе исключений часто происходят на самом низком уровне системы (например, из-за изменений в сетевой библиотеке или промежуточном ПО), поэтому изменения «всплывают» через длинные цепочки вызовов. В большой кодовой базе это может означать, что никто не сможет обновиться до новой версии библиотеки, пока не будет изменён последний пользователь. Если use() является частью библиотеки, её обновление может оказаться невозможным, поскольку изменение может затронуть неизвестных клиентов.
Политика позволять исключениям распространяться до функции, которая потенциально может с ними справиться, доказала свою состоятельность на протяжении многих лет.
Примечание
Нет. Это не стало бы лучше, даже если бы спецификации исключений были статически проверяемы. Например, см. Stroustrup94.
Примечание
Если исключение не может быть брошено, используйте noexcept.
Контроль
Отмечайте каждую спецификацию исключений.