Пространства имён
Варианты
Действия

Спецификация динамического исключения (до C++17)

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

Перечисляет исключения, которые прямо или косвенно может генерировать функция.

Содержание

[править]Синтаксис

throw(список-идентификаторов-типов (необязательно)) (1) (устарело в C++11)
(удалено в C++17)
1) Спецификация явного динамического исключения.
список-идентификаторов-типов разделённый запятыми список идентификаторов-типов, за идентификатором типа, представляющим расширение пакета, следует многоточие (...)(начиная с C++11)

Явная спецификация динамического исключения должна появляться только в деклараторе функции для типа функции, указателя на тип функции, ссылке на тип функции или указателя на тип функции-элемента, который является типом верхнего уровня объявления или определения, или для такого типа, появляющегося как параметр или тип возвращаемого значения в деклараторе функции.

void f()throw(int);// OK: объявление функцииvoid(*pf)()throw(int);// OK: объявление указателя на функциюvoid g(void pfa()throw(int));// OK: объявление параметра указателя на функциюtypedefint(*pf)()throw(int);// Ошибка: объявление typedef

[править]Объяснение

Если функция объявлена с типом T, указанным в её спецификации динамического исключения, функция может генерировать исключения этого типа или производного от него типа.

Неполные типы, указатели или ссылки на неполные типы, отличные от cv void*, и ссылочные типы rvalue(начиная с C++11) не допускаются в спецификации исключений. Типы массивов и функций, если они используются, настраиваются на соответствующие типы указателей, cv-квалификация верхнего уровня также отбрасывается. Разрешены пакеты параметров(начиная с C++11).

Спецификация динамического исключения, чей набор скорректированных типов пуст (после того, как все пакеты расширены)(начиная с C++11), не является генерирующей исключение. Функция со спецификацией динамического исключения, не создающей исключения, не допускает никаких исключений.

Спецификация динамического исключения не считается частью типа функции.

Если функция генерирует исключение типа, не указанного в её спецификации исключения, вызывается функция std::unexpected. Функция по умолчанию вызывает std::terminate, но её можно заменить предоставленной пользователем функцией (через std::set_unexpected), которая может вызывать std::terminate или выдавать исключение. Если исключение, вызванное std::unexpected, принимается спецификацией исключения, раскручивание стека продолжается как обычно. Если это не так, и std::bad_exception разрешено спецификацией исключения, генерируется std::bad_exception. Иначе вызывается std::terminate.

[править]Возможные исключения

Каждая функция f, указатель на функцию pf и указатель на функцию-элемент pmf имеют набор потенциальных исключений, который состоит из типов, которые могут быть брошены. Набор всех типов указывает, что может быть выдано любое исключение. Этот набор определяется следующим образом:

1) Если в объявлении f, pf или pmf используется спецификация динамического исключения, которая не допускает всех исключений(до C++11), набор состоит из типов, перечисленных в этой спецификации.
2) Иначе, если в объявлении f, pf или pmf используется noexcept(true), набор пуст.
(начиная с C++11)
3) Иначе набор является набором всех типов.

Примечание. Для неявно объявленных специальных функций-элементов (конструкторов, операторов присваивания и деструкторов) и для наследуемых конструкторов(начиная с C++11) набор потенциальных исключений представляет собой комбинацию наборов всех потенциальных исключений, которые они будут вызывать: конструкторы/операторы присваивания/деструкторы невариантных нестатических элементов данных, прямые базовые классы и, где это уместно, виртуальные базовые классы (включая выражения аргументов по умолчанию, как всегда).

Каждое выражение e имеет набор потенциальных исключений. Набор пуст, если e является основным константным выражением, иначе это объединение наборов потенциальных исключений всех непосредственных подвыражений e (включая выражения аргументов по умолчанию), в сочетании с другим набором, зависящим от формы e, следующим образом:

1) Если e является выражением вызова функции, пусть g обозначает вызываемую функцию, указатель на функцию или указатель на функцию-элемент, тогда
  • если в объявлении g используется спецификация динамического исключения, набор потенциальных исключений g добавляется к набору;
  • если в объявлении g используется noexcept(true), набор пуст;
(начиная с C++11)
  • иначе набор является набором всех типов.
2) Если e неявно вызывает функцию (это операторное выражение, и оператор перегружен, это выражение new и функция распределения памяти перегружена, или это полное выражение и вызывается деструктор временного объекта), то набор является набором этой функции.
3) Если e является выражением throw, то набор представляет собой исключение, которое будет инициализировано его операндом, или набор всех типов для повторного создания выражения throw (без операнда).
4) Если e является dynamic_cast ссылкой на полиморфный тип, набор состоит из std::bad_cast.
5) Если e является typeid, применённым к разыменованному указателю на полиморфный тип, набор состоит из std::bad_typeid.
6) Если e является выражением new с неконстантным размером массива, а выбранная функция распределения имеет непустой набор потенциальных исключений, набор состоит из std::bad_array_new_length.
(начиная с C++11)
void f()throw(int);// набор f() равен "int"void g();// набор g() это набор всех типов   struct A { A();};// набор "new A" это набор всех типовstruct B { B()noexcept;};// набор "B()" пустstruct D(){ D()throw(double);};// набор new D это набор всех типов

Все неявно объявленные функции-элементы и наследуемые конструкторы (начиная с C++11)имеют спецификации исключений, выбранные следующим образом:

  • Если набор потенциальных исключений является набором всех типов, неявная спецификация исключения разрешает все исключения (спецификация исключения считается присутствующей, даже если она невыразима в коде и ведёт себя так, как будто спецификация исключения отсутствует)(до C++11)это noexcept(false)(начиная с C++11).
  • Иначе, если набор потенциальных исключений не пуст, в спецификации неявного исключения перечислены все типы из набора.
  • Иначе неявная спецификация исключения имеет вид throw()(до C++11)noexcept(true)(начиная с C++11).
struct A { A(int=(A(5), 0))noexcept; A(const A&)throw(); A(A&&)throw(); ~A()throw(X);};   struct B { B()throw(); B(const B&)=default;// спецификация исключения "noexcept(true)" B(B&&, int=(throw Y(), 0))noexcept; ~B()throw(Y);};   int n =7;struct D :public A, public B {// Может генерировать (исключение типа, которое соответствует обработчику типа)// std​::bad_array_new_length, но не генерировать исключение неправильного// распределения памяти(void*) new (std::nothrow)int[n];   // D может иметь следующие неявно объявленные элементы:// D::D() throw(X, std::bad_array_new_length);// D::D(const D&) noexcept(true);// D::D(D&&) throw(Y);// D::~D() throw(X, Y);};

[править]Пример

Примечание: лучше компилировать в режиме C++98, чтобы избежать предупреждений. Несовместим с C++17 и более новыми версиями.

#include <cstdlib>#include <exception>#include <iostream>   class X {};class Y {};class Z :public X {};class W {};   void f()throw(X, Y){bool n =false;if(n)throw X();// OK, вызовет std::terminate()if(n)throw Z();// также OKthrow W();// вызовет std::unexpected()}   void handler(){std::cerr<<"Это было неожиданно!\n";// требуется сбросstd::abort();}   int main(){std::set_unexpected(handler); f();}

Вывод:

Это было неожиданно!

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 25 C++98 поведение присваивания и инициализации между указателями
на элементы с разными спецификациями исключений не указано
применено ограничение для указателей на
функции и ссылок
CWG 973 C++98 спецификация исключения может содержать типы функций, но
не указано соответствующее преобразование указателя на
функцию
определено
CWG 1267 C++11 ссылочные типы rvalue были разрешены в спецификациях
исключений
не разрешены
CWG 1351 C++98
C++11
аргумент по умолчанию (C++98) и инициализатор элемента по
умолчанию (C++11) игнорировались в неявной спецификации
исключений
не игнорируются
CWG 1777 C++11 спецификация throw(T...) не является спецификацией, не
допускающей выбрасывания исключения, даже если T
является пустым пакетом
не выбрасывает исключение, если пакет пуст
CWG 2191 C++98 набор потенциальных исключений выражения typeid может
содержать bad_typeid, даже если его нельзя сгенерировать
содержит bad_typeid, только если его можно
выбросить

[править]Смотрите также

спецификатор noexcept(C++11) указывает, может ли функция генерировать исключения[править]
close