Исключения
Обработка исключений предоставляет способ передачи управления и информации из некоторой точки выполнения программы обработчику, связанному с ранее пройденной точкой выполнения (другими словами, обработка исключений передает управление вверх по стеку вызовов).
Исключение может быть выброшено выражением throw, dynamic_cast, typeid, выражением new, функцией выделения памяти allocation function и любой из функций стандартной библиотеки, которые, как указано, выбрасывают исключения для сигнализации об определённых ошибках (например, std::vector::at, std::string::substr, и т.д.).
Для того, чтобы исключение было перехвачено, выражение throw должно находиться внутри блока try или внутри функции, вызываемой из блока try, и должен быть обработчик catch, который соответствует типу объекта исключения.
При объявлении функции могут быть указаны спецификации, ограничивающие типы исключений, которые может выбросить функция:
| (до C++17) |
| (с C++11) |
Ошибки, возникающие во время обработки исключений, обрабатываются std::terminate и std::unexpected(до C++17).
Использование
Хотя выражение throw может быть использовано для передачи управления произвольному блоку кода вверх по стеку выполнения по произвольным причинам (похоже на std::longjmp), его предполагаемое использование — обработка ошибок.
Обработка ошибок
Выбрасывание исключения используется для сигнализации об ошибках из функций, где «ошибки» обычно ограничиваются следующим [1][2][3]:
- Невыполнение постусловий, таких как невозможность создания объекта-значения возврата.
- Невыполнение предопределённых условий другой функции, которая должна быть вызвана.
- (для не-приватных функций-членов) Невозможность (восстановления) инварианта класса.
В частности, это подразумевает, что ошибки конструкторов (см. также RAII) и большинства операторов должны сигнализироваться с помощью исключений.
Кроме того, так называемые функции с «широким контрактом» используют исключения для указания неприемлемых входных данных, например, std::string::at не имеет условий, но выбрасывает исключение для указания выхода за пределы индекса.
Безопасность при возникновении исключений
После того, как об ошибке сообщили из функции, могут быть предоставлены дополнительные гарантии относительно состояния программы. Обычно признаются следующие четыре уровня гарантий исключений [4][5][6], которые являются строгими надмножествами друг друга:
- Гарантия отсутствия исключений (или гарантия успешного выполнения) — функция никогда не выбрасывает исключений. От гарантии отсутствия исключений (ошибки сообщаются другими способами или скрываются) ожидается от деструкторов и других функций, которые могут быть вызваны во время разворачивания стека. Деструкторы по умолчанию
noexcept.(с C++11) От гарантии успешного выполнения (функция всегда выполняется успешно) ожидается от операций обмена, конструкторов перемещения и других функций, используемых теми, которые обеспечивают сильную гарантию исключений. - Сильная гарантия исключений — Если функция выбрасывает исключение, состояние программы откатывается до состояния перед вызовом функции (например,
std::vector::push_back). - Базовая гарантия исключений — Если функция выбрасывает исключение, программа находится в корректном состоянии. Ресурсы не утечкаются, а все инварианты объектов сохранены.
- Гарантия отсутствия исключений — Если функция выбрасывает исключение, программа может оказаться в некорректном состоянии: могут произойти утечки ресурсов, повреждение памяти или другие ошибки нарушения инвариантов.
Кроме того, общие компоненты могут предлагать нейтральную по отношению к исключениям гарантию: если исключение выбрасывается параметром шаблона (например, из объекта-функции Compare из std::sort или из конструктора T в std::make_shared), оно передаётся вызывающей стороне без изменений.
Объекты исключений
Хотя объекты любого полного типа и указатели cv на void могут быть выброшены как объекты исключений, все функции стандартной библиотеки выбрасывают анонимные временные объекты по значению, и типы этих объектов выводятся (прямо или косвенно) из std::exception. Пользовательские исключения обычно следуют этой модели.[7][8][9]
Чтобы избежать ненужного копирования объекта исключения и обрезки объекта, лучшей практикой для блоков catch является перехват по ссылке.[10][11][12][13]
Внешние ссылки
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/exceptions