Система исключений в C++ основана на механизме try-catch и ключевом слове throw. При возникновении исключительной ситуации (например, ошибка ресурса, нарушения инварианта), внутри блока try инициируется (бросается) исключение через оператор throw. Операции по поиску подходящего обработчика (catch) осуществляются путём показа стека до первого совпадающего типа.
Важные детали:
std::exception).noexcept.Проектирование:
catch(const std::exception& e).Пример кода:
#include <iostream> #include <stdexcept> void mayFail(bool fail) { if (fail) throw std::runtime_error("Ошибка процесса"); } int main() { try { mayFail(true); } catch (const std::exception& ex) { std::cout << "Поймано исключение: " << ex.what() << std::endl; } }
Что произойдёт, если исключение будет выброшено из деструктора во время передачи другого исключения вверх по стеку?
Ответ: Произойдёт аварийное завершение программы через вызов std::terminate(), потому что во время обработки исключения не допускается генерация нового исключения (double exception), иначе нарушается stack unwinding.
Пример:
struct CrashOnDestruct { ~CrashOnDestruct() noexcept(false) { throw std::runtime_error("Ошибка в деструкторе!"); } }; void func() { CrashOnDestruct obj; throw std::logic_error("Обработка ошибки"); } int main() { try { func(); } catch (...) { } } // Завершится через std::terminate()
История
Внутри крупного финансового приложения исключения бросались из деструктора класса-обёртки над базой данных. Одна из опорных транзакций при возникновении ошибки инициировала исключение, при unwind-выходе вызывался деструктор, который также кидал ошибку. Всё приложение аварийно завершалось, теряя работу пользователей. Разработчикам пришлось срочно заменить throw в деструкторах на запись логов и корректную обработку.
История
Микросервис обрабатывал исключения по типу: catch(std::exception). Один из потоков бросал исключения пользовательских типов (не наследовались от std::exception). Такие ошибки не отлавливались, происходил неожиданный обрыв соединения и утечка памяти.
История
Отсутствие спецификатора noexcept в методах перемещения контейнеров привело к тому, что стандартная библиотека использовала медленную копию вместо быстрой move-операции; существенный провал в производительности был выявлен только на нагрузочных тестах.