Spec-Zone.ru › C++

throw выражение

Сигнализирует об ошибочном состоянии и выполняет обработчик ошибок.

Синтаксис

throw выражение (1)
throw (2)

Объяснение

См. блок try-catch для получения дополнительной информации о блоках try и catch (обработчик исключений)1) Сначала копирует объект исключения из выражения
  • Это может вызвать конструктор перемещения для выражения-ссылок на временные объекты. Даже если копирование выбрало конструктор перемещения, копирование из ссылки на переменную должно быть допустимым, и деструктор должен быть доступен
(с C++11)
  • Это также может вызвать конструктор перемещения для выражений, которые называют локальные переменные или параметры функции или catch пункта, область действия которых не выходит за пределы самого внутреннего блока try (если есть), по тем же правилам разрешения перегрузки, что и в операторе возврата
(с C++17)
  • Копирование/перемещение(с C++11) может быть подвержено исключению копирования
затем передает управление обработчику исключения с подходящим типом, для которого составное выражение или список инициализации членов, которые следуют за ключевым словом try, были в последний раз введены и не выведены этой нитью выполнения.
2) Перебрасывает текущее обрабатываемое исключение. Прерывает выполнение текущего catch блока и передает управление следующему соответствующему обработчику исключений (но не другому catch пункту после того же try блока: его составное выражение считается «выведенным»), повторно используя существующий объект исключения: новые объекты не создаются. Эта форма разрешена только тогда, когда в настоящее время обрабатывается исключение (в противном случае она вызывает std::terminate). catch пункт, связанный с блоком функции try, должен выйти посредством повторного выбрасывания, если используется в конструкторе.

См. std::terminate и std::unexpected(до C++17) для обработки ошибок, возникающих во время обработки исключений.

Объект исключения

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

Преобразования массив-указатель и функция-указатель выполняются над выражением. Тип объекта исключения определяется путём удаления любых квалификаторов уровня cv из типа выражения (возможно, после преобразований), и объект исключения копируется из выражения (возможно, после преобразований).

Если тип объекта исключения будет неполным типом, абстрактным классом или указателем на неполный тип, отличным от указателя на (возможно, с квалификаторами cv) void, программа неверна.

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

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

Объект исключения сохраняется до тех пор, пока последний пункт catch не выйдет, не произойдёт повторное перебрасывание (если не переброшено, он уничтожается немедленно после уничтожения параметра пункта catch), или до тех пор, пока последний std::exception_ptr который ссылается на этот объект, не будет уничтожен (в этом случае объект исключения уничтожается непосредственно перед возвратом деструктора std::exception_ptr).

Развертывание стека

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

По мере продвижения потока управления по стеку вызовов вызываются деструкторы для всех объектов с автоматическим сроком жизни, которые были созданы, но ещё не уничтожены, с момента входа в соответствующий блок try, в обратном порядке завершения их конструкторов. Если исключение выбрасывается из деструктора локальной переменной или временного объекта, используемого в операторе return, также вызывается деструктор для объекта, возвращаемого из функции.

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

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

(с C++11)

Если исключение выбрасывается из конструктора, который вызывается выражением new, вызывается соответствующая функция освобождения operator delete, если она доступна.

Этот процесс называется развертыванием стека.

Если любая функция, которая вызывается непосредственно механизмом развертывания стека, после инициализации объекта исключения и перед началом обработчика исключений, завершается с исключением, вызывается std::terminate. К таким функциям относятся деструкторы объектов с автоматическим сроком жизни, область действия которых выходит за пределы, и конструктор копирования объекта исключения, который вызывается (если не исключен) для инициализации аргументов catch по значению.

Если исключение выбрасывается и не перехватывается, в том числе исключения, которые выходят за пределы исходной функции std::thread, основной функции и конструктора или деструктора любых статических или локальных объектов потока, вызывается std::terminate. Реализация определяет, происходит ли любое развертывание стека для непрохваченных исключений.

Примечания

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

try
{
    std::string("abc").substr(10); // throws std::out_of_range
}
catch (const std::exception& e)
{
    std::cout << e.what() << '\n';
//  throw e; // copy-initializes a new exception object of type std::exception
    throw;   // rethrows the exception object of type std::out_of_range
}

Выражение throw классифицируется как выражение prvalue типа void. Как и любое другое выражение, оно может быть подвыражением в другом выражении, чаще всего в условном операторе:

double f(double d)
{
    return d > 1e7 ? throw std::overflow_error("too big") : d;
}
 
int main()  
{
    try
    {
        std::cout << f(1e10) << '\n';
    }
    catch (const std::overflow_error& e)
    {
        std::cout << e.what() << '\n';
    }
}

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

throw

Пример

#include <iostream>
#include <stdexcept>
 
struct A
{
    int n;
 
    A(int n = 0): n(n) { std::cout << "A(" << n << ") constructed successfully\n"; }
    ~A() { std::cout << "A(" << n << ") destroyed\n"; }
};
 
int foo()
{
    throw std::runtime_error("error");
}
 
struct B
{
    A a1, a2, a3;
 
    B() try : a1(1), a2(foo()), a3(3)
    {
        std::cout << "B constructed successfully\n";
    }
    catch(...)
    {
            std::cout << "B::B() exiting with exception\n";
    }
 
    ~B() { std::cout << "B destroyed\n"; }
};
 
struct C : A, B
{
    C() try
    {
        std::cout << "C::C() completed successfully\n";
    }
    catch(...)
    {
        std::cout << "C::C() exiting with exception\n";
    }
 
    ~C() { std::cout << "C destroyed\n"; }
};
 
int main () try
{
    // creates the A base subobject
    // creates the a1 member of B
    // fails to create the a2 member of B
    // unwinding destroys the a1 member of B
    // unwinding destroys the A base subobject
    C c;
}
catch (const std::exception& e)
{
    std::cout << "main() failed to create C with: " << e.what();
}

Вывод:

A(0) constructed successfully
A(1) constructed successfully
A(1) destroyed
B::B() exiting with exception
A(0) destroyed
C::C() exiting with exception
main() failed to create C with: error

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применимо к Поведение, опубликованное в спецификации Корректное поведение
CWG 499 C++98 массив с неизвестной границей не мог быть брошен, потому что
его тип неполный, но объект исключения может быть
создан из указателя, лишенного квалификатора, без проблем
применить требование завершения типа
к объекту исключения вместо этого
CWG 668 C++98 std::terminate не вызывался, если исключение выбрасывается
из деструктора локального неавтоматического объекта
вызвать std::terminate
в этом случае
CWG 1863 C++11 конструктор копирования не требовался для объектов исключений,
только для перемещения при выбрасывании, но копирование
разрешалось позже
необходим конструктор копирования
CWG 1866 C++98 члены варианта утекали при разворачивании стека из конструктора члены варианта разрушаются
CWG 2176 C++98 выброс из деструктора локальной переменной
мог пропустить деструктор возвращаемого значения функции
значение, возвращаемое функцией,
добавлено в разворачивание стека
CWG 2699 C++98 throw "EX" фактически выбрасывал char* вместо const char* исправлено
CWG 2711 C++98 источник копирующего инициализирования
объекта исключения не был указан
скопировано из
выражения

См. также

  • исключение копирования
  • try-catch блок
  • noexcept спецификатор
  • динамические спецификации исключений

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

Spec-Zone.ru

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