Spec-Zone.ru › C++

Блок try

Связывает один или несколько обработчиков исключений (блоков catch) с составным оператором.

Синтаксис

try составной оператор последовательность_обработчиков

где последовательность_обработчиков — это последовательность одного или нескольких обработчиков, имеющих следующий синтаксис:

catch ( атрибут (необязательно) последовательность_спецификаторов_типа декларатор ) составной оператор (1)
catch ( атрибут (необязательно) последовательность_спецификаторов_типа абстрактный_декларатор (необязательно) ) составной оператор (2)
catch ( ... ) составной оператор (3)
составной оператор - заключённая в фигурные скобки последовательность операторов
атрибут - любое количество атрибутов (с C++11), применяется к формальному параметру
последовательность_спецификаторов_типа - часть объявления формального параметра, аналогично списку параметров функции
декларатор - часть объявления формального параметра, аналогично списку параметров функции
абстрактный_декларатор - часть объявления безымянного формального параметра, аналогично списку параметров функции
1) Блок catch, объявляющий именованный формальный параметр
try { /* */ } catch (const std::exception& e) { /* */ }
2) Блок catch, объявляющий безымянный параметр
try { /* */ } catch (const std::exception&) { /* */ }
3) Обработчик «всех исключений», который активируется для любого исключения
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)
  • T является (возможно cv-квалифицированным) U или const U&, где U является указателем или указателем на член типа, а E является std::nullptr_t.
(с 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, std::current_exception может быть использован для захвата исключения в std::exception_ptr, и std::throw_with_nested может быть использован для построения вложенных исключений.

(с 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, throw

Пример

Следующий пример демонстрирует несколько вариантов использования блока 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API