Spec-Zone.ru › C++

Обработка исключений

Исключение может быть обработано обработчиком.

Обработчик

catch ( attr (необязательно) type-specifier-seq declarator ) compound-statement (1)
catch ( attr (необязательно) type-specifier-seq abstract-declarator (необязательно) ) compound-statement (2)
catch ( ... ) compound-statement (3)
1) Обработчик с именованным параметром.
2) Обработчик с безымянным параметром.
3) Обработчик, соответствующий исключениям всех типов.
attr - (начиная с C++11) любое количество атрибутов, применяемых к параметру
type-specifier-seq - часть объявления формального параметра, такая же, как в списке параметров функции
declarator - часть объявления параметра, такая же, как в списке параметров функции
abstract-declarator - часть объявления безымянного параметра, такая же, как в списке параметров функции
compound-statement - составной оператор


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

Если параметр объявлен с одним из следующих типов, программа некорректна:

  • неполный тип
  • абстрактный тип класса
  • тип ссылки на rvalue
(начиная с C++11)
  • указатель на неполный тип, отличный от (возможно, cv-квалифицированного) void
  • ссылка lvalue на неполный тип

Если параметр объявлен как «массив типа T» или имеет функциональный тип T, его тип корректируется до «указателя на T».

Обработчик с типом параметра T можно кратко назвать «обработчиком типа T».

Соответствие исключений

Каждый блок try связан с несколькими обработчиками, которые образуют последовательность обработчиков. Когда из блока try выбрасывается исключение, обработчики этой последовательности проверяются на соответствие исключению в порядке их появления.

Обработчик соответствует объекту исключения типа E, если выполняется любое из следующих условий:

  • Обработчик имеет тип «возможно cv-квалифицированный T» или «ссылка lvalue на возможно cv-квалифицированный T», и выполняется одно из следующих условий:
    • E и T являются одним и тем же типом (без учета cv-квалификаторов верхнего уровня).
    • T является однозначным открытым базовым классом E.
  • Обработчик имеет тип «возможно cv-квалифицированный T» или constT&, где T является типом указателя или указателя на член, и выполняется одно из следующих условий:
  • E является типом указателя или указателя на член, который можно преобразовать в T одним или несколькими из следующих способов:
    • Стандартное преобразование указателя, не включающее преобразование в указатели на закрытые, защищенные или неоднозначные классы.
  • Преобразование указателя на функцию.
(начиная с C++17)
  • Преобразование квалификации.
  • E является std::nullptr_t.
(начиная с C++11)

Обработчик catch (...) соответствует исключениям любого типа. Если он присутствует, то может быть только последним в последовательности обработчиков. Такой обработчик может использоваться, чтобы гарантировать, что из функции, предоставляющей гарантию отсутствия исключений, не смогут выйти неперехваченные исключения.

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

Если среди обработчиков блока try соответствие не найдено, поиск подходящего обработчика продолжается в динамически окружающем блоке try того же потока(начиная с C++11).

Если подходящий обработчик не найден, вызывается std::terminate; будет ли стек размотан до этого вызова std::terminate, определяется реализацией.

Обработка исключений

При выбрасывании исключения управление передается ближайшему обработчику с подходящим типом; «ближайший» означает обработчик, составной оператор или список инициализаторов членов которого (если он есть), следующий за ключевым словом try, был последним, в который вошел поток управления и из которого он еще не вышел.

Инициализация параметра обработчика

Параметр, объявленный в списке параметров (если он есть) и имеющий тип «возможно cv-квалифицированный T» или «ссылка lvalue на возможно cv-квалифицированный T», инициализируется из объекта исключения типа E следующим образом:

  • Если T является базовым классом E, параметр копирующе инициализируется из lvalue типа T, обозначающего соответствующий подобъект базового класса объекта исключения.
  • В противном случае параметр копирующе инициализируется из lvalue типа E, обозначающего объект исключения.

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

Если параметр объявлен как объект, любые изменения этого объекта не повлияют на объект исключения.

Если параметр объявлен как ссылка на объект, любые изменения объекта, на который она ссылается, являются изменениями объекта исключения и повлияют на него, если этот объект будет повторно выброшен.

Активация обработчика

Обработчик считается активным, когда завершается инициализация его параметра (если он есть).

Кроме того, неявный обработчик считается активным, когда из-за выбрасывания исключения управление передается в std::terminate.

Обработчик перестает считаться активным при выходе из него.

Исключение, обработчик которого был активирован последним и все еще активен, называется текущим обрабатываемым исключением. Такое исключение можно выбросить повторно.

Поток управления

compound-statement обработчика является оператором с ограниченным потоком управления:

void f()
{
    goto label;     // error
    try
    {
        goto label; // error
    }
    catch (...)
    {
        goto label: // OK
        label: ;
    }
}

Примечания

Размотка стека происходит во время передачи управления обработчику. Когда обработчик становится активным, размотка стека уже завершена.

Исключение, выброшенное выражением throw throw 0, не соответствует обработчику типа указателя или указателя на член.

  • throw nullptr можно использовать вместо него, чтобы выбросить нулевой указатель, соответствующий таким обработчикам.
(начиная с C++11)

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

Можно написать обработчики, которые никогда не будут выполнены, например разместив обработчик для конечного производного класса после обработчика для соответствующего однозначного открытого базового класса:

try
{
    f();
}
catch (const std::exception& e)
{} // will be executed if f() throws std::runtime_error
catch (const std::runtime_error& e)
{} // dead code!

Во многих реализациях разрешение вопроса CWG 388 чрезмерно распространяется на обработчики со ссылкой на неконстантные типы указателей:

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
}

Ключевые слова

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++.

DR Применено к Опубликованное поведение Корректное поведение
CWG 98 C++98 оператор switch может передать управление обработчику запрещено
CWG 210 C++98 выражения throw сопоставлялись с обработчиками с обработчиками сопоставляются
объекты исключений
CWG 388 C++98 исключение типа «указатель» или «указатель на член»
не могло быть сопоставлено с константной ссылкой на другой тип
сопоставление стало возможным,
если типы преобразуемы
CWG 1166 C++98 поведение не было определено, если сопоставлялся обработчик,
тип которого является ссылкой на абстрактный тип класса
абстрактные типы классов
не допускаются для обработчиков
CWG 1769 C++98 если тип обработчика является базовым для типа
объекта исключения, для инициализации параметра
обработчика мог использоваться преобразующий конструктор
параметр копирующе инициализируется
из соответствующего подобъекта базового класса
объекта исключения
CWG 2093 C++98 объект исключения типа «указатель на объект» нельзя было сопоставить с
обработчиком типа «указатель на объект» посредством преобразования квалификации
разрешено

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
    • 14.4 Обработка исключения [except.handle]
  • Стандарт C++20 (ISO/IEC 14882:2020):
    • 14.4 Обработка исключения [except.handle]
  • Стандарт C++17 (ISO/IEC 14882:2017):
    • 18.3 Обработка исключения [except.handle]
  • Стандарт C++14 (ISO/IEC 14882:2014):
    • 15.3 Обработка исключения [except.handle]
  • Стандарт C++11 (ISO/IEC 14882:2011):
    • 15.3 Обработка исключения [except.handle]
  • Стандарт C++03 (ISO/IEC 14882:2003):
    • 15.3 Обработка исключения [except.handle]
  • Стандарт C++98 (ISO/IEC 14882:1998):
    • 15.3 Обработка исключения [except.handle]

См. также

  • Блок try
  • Выбрасывание исключений
  • Обработка исключений

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/catch

Spec-Zone.ru

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