История вопроса:
Механизм обработки исключений был введён в C++ для обеспечения более надёжной и структурированной обработки ошибок, в отличие от кодов возврата. С годами синтаксис расширился, появились спецификаторы типа noexcept для контроля отмены выбрасывания исключений из функций.
Проблема:
Неправильная работа с исключениями часто приводит к утечкам памяти, неопределённому поведению или падению приложений. Если не учесть бросание исключений из конструкторов, деструкторов или при работе с ресурсами, возникает серьёзная проблема с состоянием программы.
Решение:
Базовый синтаксис — использование try-catch. Исключения могут быть любого типа, но рекомендуется наследовать пользовательские от std::exception. Ключевое слово noexcept (C++11+) указывает, что функция не должна выбрасывать исключения; бросок исключения из noexcept-функции вызывает std::terminate().
Пример кода:
#include <iostream> #include <stdexcept> void func() noexcept(false) { throw std::runtime_error("Error!"); } int main() { try { func(); } catch(const std::exception& ex) { std::cout << ex.what(); } }
Ключевые особенности:
Допустимо ли бросать исключения в деструкторе?
Нет, бросок исключения из деструктора во время стекового развёртывания приводит к std::terminate(). Исключения в деструкторе надо перехватывать внутри самого деструктора.
Что произойдёт, если выбросить исключение из noexcept-функции?
Вызовется std::terminate, программа аварийно завершится. noexcept — строгий контракт.
Можно ли ловить исключения по value? Чем это опасно?
Ловить по value можно, но объект копируется (object slicing). Рекомендуется использовать const &.
Пример кода:
try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }
Код выбрасывал исключения в деструкторах ресурсов; при аварийном завершении стек развёртывался некорректно, ресурсы остались утечкой.
Плюсы:
Минусы:
Критичные методы были помечены noexcept, деструкторы обрабатывали все исключения внутри себя. Применялись catch по ссылке, все ошибки логировались.
Плюсы:
Минусы: