Обработка исключений: try, catch, throw

Что происходит, когда программа сталкивается с ошибкой, которую нельзя «просто проигнорировать»: деление на ноль, выход за границу массива, некорректный ввод. Сравните, как ведёт себя код без обработки и с ней.

try / catch throw Свои классы исключений

Сценарий

Стек вызовов

Запустите программу, чтобы увидеть путь выполнения.

Вывод программы

$ ./program

Выберите режим и нажмите «Запустить».

Код

main.cpp

Как работает try / catch / throw

Общий шаблон
try {
    // код, который может завершиться ошибкой
    if (что_то_не_так)
        throw SomeException("пояснение");   // бросаем исключение

    // продолжение обычной работы
} catch (SomeException &e) {
    // обрабатываем ошибку
    cout << "Ошибка: " << e.what() << endl;
} catch (...) {
    // перехват любого другого исключения
    cout << "Неизвестная ошибка" << endl;
}
Ключевая идея. throw «выбрасывает» объект-исключение и прерывает нормальное выполнение функции. Управление передаётся первому подходящему catch в стеке вызовов. Если такого нет — программа завершается аварийно.
Свои классы исключений. Наследуйте их от std::exception и переопределяйте метод what() — так вы получаете осмысленные сообщения и можете обрабатывать разные ошибки разными ветками catch.

Задание

  1. В сценарии «деление на ноль» установите b = 0 и запустите без обработки. Что показывает программа? А теперь включите try/catch.
  2. Для сценария «выход за границу массива» введите индекс 10 при размере 5. Сравните поведение.
  3. Почему catch (...) должен идти последним? Что будет, если поставить его первым?
  4. Определите свой класс ValidationError, унаследованный от std::exception, и используйте его для проверки возраста.
  5. Объясните: почему нельзя бросать исключение прямо в конструкторе класса без обработки в вызывающем коде?