Я изучаю спецификатор noexcept
и задаюсь вопросом о причине некоторых его дизайнерских решений. В частности, причина, по которой он не выполняет такие же проверки времени компиляции, как, например, спецификатор constexpr
. Я объясню это утверждение позже.
Это код, который я тестирую:
#include <iostream>
#include <stdexcept>
void g()
{
throw std::runtime_error("EXCEPT");
}
void f() noexcept
{
g();
}
int main()
{
try
{
f();
}
catch(const std::exception & e)
{
std::cout << "Caught this: " << e.what() << std::endl;
}
return 0;
}
Эта версия кода компилируется, но падает, потому что (если я правильно понимаю) со спецификатором noexcept
компилятор только что "доверился мне" и сделал оптимизацию, которая не позволит коду во время выполнения обрабатывать какое-либо исключение, несмотря на try
/catch
блок.
Чего я не понимаю: почему компилятор не проверяет такую простую вещь, как подпись g()
? g()
не был объявлен noexcept
, поэтому, не прибегая к дорогостоящей проверке, действительно ли он выдает или нет, код следует просто считать неправильным, потому что g()
неявно является noexcept(false)
. В каком случае это полезно?
Чтобы работать так, как я лично ожидал, я должен изменить подпись f()
следующим образом:
void f() noexcept(noexcept(g()))
{
g();
}
Теперь спецификатор noexcept
в объявлении f()
применяется только в том случае, если он присутствует и в объявлении g()
. Во время выполнения исключение прекрасно обрабатывается. Почему это не по умолчанию? Если f()
вызывает множество функций, выполнение noexcept(noexcept(g()))
для каждой вызываемой функции вручную становится адом обслуживания.
Я процитировал спецификатор constexpr
, потому что он фактически заставляет компилятор проверять, что все функции, вызываемые функцией constexpr
, сами объявлены как constexpr
. Итак, я думаю, что причина, по которой noexcept
не делает то же самое, связана со временем компиляции.
Подводя итоги вопроса: почему компилятор не проверяет, что функции, вызываемые функцией noexcept
, сами объявлены как noexcept
?