Блок try
Связывает один или несколько обработчиков исключений (блоков catch) с составным оператором.
Синтаксис
try составной оператор последовательность_обработчиков |
где последовательность_обработчиков — это последовательность одного или нескольких обработчиков, имеющих следующий синтаксис:
catch ( атрибут (необязательно) последовательность_спецификаторов_типа декларатор ) составной оператор | (1) | |
catch ( атрибут (необязательно) последовательность_спецификаторов_типа абстрактный_декларатор (необязательно) ) составной оператор | (2) | |
catch ( ... ) составной оператор | (3) |
| составной оператор | - | заключённая в фигурные скобки последовательность операторов |
| атрибут | - | любое количество атрибутов (с C++11), применяется к формальному параметру |
| последовательность_спецификаторов_типа | - | часть объявления формального параметра, аналогично списку параметров функции |
| декларатор | - | часть объявления формального параметра, аналогично списку параметров функции |
| абстрактный_декларатор | - | часть объявления безымянного формального параметра, аналогично списку параметров функции |
try { /* */ } catch (const std::exception& e) { /* */ }try { /* */ } catch (const std::exception&) { /* */ }try { /* */ } catch (...) { /* */ }Описание
См. исключения throw для получения дополнительной информации об выражениях throw.Блок try — это оператор, и как таковой может располагаться там, где может располагаться любой оператор (то есть, как один из операторов в составном операторе, включая тело функции). См. function-try-block для блоков try вокруг тел функций. Следующее описание относится как к блокам try, так и к function-try-blocks.
Формальный параметр блока catch (последовательность_спецификаторов_типа и декларатор или последовательность_спецификаторов_типа и абстрактный_декларатор) определяет, какие типы исключений вызовут вход в этот блок catch. Он не может быть неполным типом, абстрактным классом, ссылкой на rvalue, (с C++11) или указателем на неполный тип (за исключением указателей на (возможно cv-квалифицированные) void). Если тип формального параметра — массив или функция, он обрабатывается как соответствующий указатель (аналогично объявлению функции).
Когда исключение выбрасывается каким-либо оператором в составном операторе, объект исключения типа E сопоставляется с типами формальных параметров T каждого блока catch в последовательности_обработчиков в порядке их перечисления. Исключение является соответствием, если выполняется одно из следующих условий:
-
EиTявляются одним и тем же типом (не учитывая верхнеуровневые cv-квалификаторы наT) -
Tявляется ссылкой на (возможно cv-квалифицированный)E -
Tявляется недвусмысленным публичным базовым классомE -
Tявляется ссылкой на недвусмысленный публичный базовый классE -
Tявляется (возможно cv-квалифицированным)Uилиconst U&, иUявляется указателем или указателем на член типа, аEтакже является указателем или указателем на член типа, неявно преобразуемый кUодним или несколькими способами: - стандартным преобразованием указателей, отличным от преобразования к частному, защищенному или неоднозначному базовому классу
- преобразованием квалификаций
| (с C++17) |
| (с C++11) |
try
{
f();
}
catch (const std::overflow_error& e)
{} // this executes if f() throws std::overflow_error (same type rule)
catch (const std::runtime_error& e)
{} // this executes if f() throws std::underflow_error (base class rule)
catch (const std::exception& e)
{} // this executes if f() throws std::logic_error (base class rule)
catch (...)
{} // this executes if f() throws std::string or int or any other unrelated typeБлок catch-all catch (...) соответствует исключениям любого типа. Если он присутствует, он должен быть последним блоком catch в последовательности_обработчиков. Блок catch-all может использоваться для гарантии того, что никакие необработанные исключения не могут вырваться из функции, которая предоставляет гарантию отсутствия исключений.
Если после проверки всех блоков catch соответствие не найдено, распространение исключения продолжается в содержащий блок try, как описано в выражении throw. Если нет содержащих блоков try, выполняется std::terminate (в этом случае, реализация определяет, происходит ли вообще разворачивание стека: выброс необработанного исключения может завершить программу без вызова каких-либо деструкторов).
При входе в блок catch, если его формальный параметр является базовым классом типа исключения, он инициализируется копированием из подобъекта базового класса объекта исключения. В противном случае, он инициализируется копированием из объекта исключения (эта копия может быть исключена в соответствии с исключением копирования).
try
{
std::string("abc").substr(10); // throws std::length_error
}
// catch (std::exception e) // copy-initialization from the std::exception base
// {
// std::cout << e.what(); // information from length_error is lost
// }
catch (const std::exception& e) // reference to the base of a polymorphic object
{
std::cout << e.what(); // information from length_error printed
}Если параметр блока catch является типом ссылки, любые изменения, внесённые в него, отражаются в объекте исключения и могут быть замечены другим обработчиком, если исключение повторно выбрашено с помощью throw;. Если параметр не ссылка, любые изменения, внесённые в него, локальны, и его срок жизни заканчивается при выходе из обработчика.
| Внутри блока catch, | (с C++11) |
Оператор goto или switch не должен использоваться для перехода в блок try или в обработчик.
Помимо выбрасывания или повторного выбрасывания исключения, блок catch после обычного блока try (не function-try-block) может выйти с помощью return, continue, break, goto или достигнув конца составного оператора. В любом случае, это приводит к уничтожению объекта исключения (если не существует экземпляра std::exception_ptr, который ссылается на него).
Примечания
Выражение throw throw NULL; не гарантируется, что будет соответствовать блоку catch с указателем, потому что тип объекта исключения может быть int, но throw nullptr; безусловно соответствует любому блоку catch с указателем или указателем на член.
Если блок catch для производного класса расположен после блока catch для базового класса, производный блок catch никогда не будет выполнен:
try
{
f();
}
catch (const std::exception& e)
{} // will be executed if f() throws std::runtime_error
catch (const std::runtime_error& e)
{} // dead code!Если goto используется для выхода из блока try, и если любой из деструкторов переменных с автоматическим объявлением в блоке, которые выполняются goto выбрасывает исключение, эти исключения обрабатываются блоками try, в которых переменные объявлены:
label:
try
{
T1 t1;
try
{
T2 t2;
if (condition)
goto label; // destroys t2, then destroys t1, then jumps to label
}
catch (...) {} // catches the exception from the destructor of t2
}
catch (...) {} // catches the exception from the destructor of t1Многие реализации чрезмерно расширяют разрешение CWG388 для обработчиков ссылок на указатели, не являющиеся константными:
int i;
try
{
try
{
throw static_cast<float*>(nullptr);
}
catch (void*& pv)
{
pv = &i;
throw;
}
}
catch (const float* pf)
{
assert(pf == nullptr); // should pass, but fails on MSVC and Clang
}Ключевые слова
Пример
Следующий пример демонстрирует несколько вариантов использования блока try-catch
#include <iostream>
#include <vector>
int main()
{
try
{
std::cout << "Throwing an integer exception...\n";
throw 42;
}
catch (int i)
{
std::cout << " the integer exception was caught, with value: " << i << '\n';
}
try
{
std::cout << "Creating a vector of size 5... \n";
std::vector<int> v(5);
std::cout << "Accessing the 11th element of the vector...\n";
std::cout << v.at(10); // vector::at() throws std::out_of_range
}
catch (const std::exception& e) // caught by reference to base
{
std::cout << " a standard exception was caught, with message: '"
<< e.what() << "'\n";
}
}Возможный вывод:
Throwing an integer exception... the integer exception was caught, with value: 42 Creating a vector of size 5... Accessing the 11th element of the vector... a standard exception was caught, with message: 'out_of_range'
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| Отчет об ошибке | Применено к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| CWG 98 | C++98 | оператор switch может передать управление в блок try или в обработчик | запрещено |
| CWG 210 | C++98 | выражение throw сопоставлялось с блоками catch | объект исключения сопоставляется с блоками catch |
| CWG 388 | C++98 | исключение типа указателя или указателя на член не могло сопоставляться с константной ссылкой на другой тип | разрешено сопоставление при преобразовании |
| CWG 1166 | C++98 | поведение было неопределённым, когда блок catch, тип исключения которого является ссылкой на абстрактный тип класса, сопоставлялся | типы абстрактных классов не разрешены для блоков catch |
| CWG 1769 | C++98 | когда тип исключения, объявленный в блоке catch, является базой типа объекта исключения, для инициализации параметра блока catch может быть использован конструктор преобразования | параметр копируется из соответствующего подобъекта базового класса объекта исключения |
| CWG 2093 | C++98 | объект исключения типа указателя на объект не мог сопоставляться с обработчиком типа указателя на объект посредством преобразования квалификации | разрешено |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/try_catch