void f() noexcept(noexcept(g())); //
//
Если функция g()
обещает не передавать исключений, то f()
также не будет. Если g()
не имеет спецификатора исключения или имеет спецификатор, позволяющий передачу исключений, то функция f()
также может передавать их.
noexcept
имеет два значения: это спецификатор исключения, когда оно следует за списком параметров функции, и оператор, который зачастую используется как логический аргумент для спецификатора исключения noexcept
.
Хотя спецификатор noexcept
не является частью типа функции, наличие у функции спецификатора исключения влияет на ее использование.
Указатель на функцию и функция, на которую указывает этот указатель, должны иметь одинаковые спецификации. Таким образом, если объявлен указатель со спецификатором запрета передачи исключения, то использовать этот указатель можно только для указания на функции с подобным спецификатором. Указатель на функцию, способную передавать исключение, определенный явно или неявно, может указывать на любую функцию, даже если она обещает не передавать исключения:
//
void (*pf1)(int) noexcept = recoup;
//
//
void (*pf2)(int) = recoup;
pf1 = alloc; //
//
pf2 = alloc; //
Если виртуальная функция обещает не передавать исключений, унаследованные виртуальные функции также должны обещать не передавать исключений. С другой стороны, если базовая функция позволяет передачу исключения, то производным функциям стоит быть ограниченным строже и обещать не передавать их:
class Base {
public:
virtual double f1(double) noexcept; //
virtual int f2() noexcept(false); //
virtual void f3(); //
};
class Derived : public Base {
public:
double f1(double); //
int f2() noexcept (false); //
void f3() noexcept; //
};
Когда компилятор синтезирует функции-члены управления копированием, он создает для них спецификацию исключения. Если все соответствующие функции-члены всех базовых классов обещают не передавать исключений, то синтезируемые функции-члены также будут noexcept
. Если какая-нибудь функция, вызванная синтезируемым членом, может передать исключение, то этот синтезируемый член помечается как noexcept(false)
. Кроме того, если разработчик не предоставил спецификацию исключения для деструктора, который он определяет, компилятор синтезирует ее сам. Компилятор создает ту же спецификацию, которую он создал бы, будь то синтезируемый деструктор для этого класса.
Упражнение 18.8. Пересмотрите написанные классы и добавьте соответствующие спецификации исключения к их конструкторам и деструкторам. Если вы полагаете, что некоторые из ваших деструкторов могли бы передавать исключения, изменить код так, чтобы это было невозможно.
18.1.5. Иерархии классов исключений
Классы исключений (см. раздел 5.6.3) стандартной библиотеки формируют иерархию наследования (см. главу 15), представленную на рис. 18.1.
Рис. 18.1. Иерархия классов исключений стандартной библиотеки
Единственными функциями, определенными типом exception
, являются конструктор копий, оператор присвоения копий, виртуальный деструктор и виртуальная функция-член what()
. Она возвращает указатель типа const char*
на символьный массив с нулевым символом в конце и, как гарантируется, не передает никаких исключений.