Обработка исключений в C++: практические примеры try, catch, throw
Что такое обработка исключений в C++?
Обработка исключений позволяет C++ программам корректно восстанавливаться после непредвиденных ошибок во время выполнения. Когда возникает ошибка, управление переходит к специальному обработчику, который решает, как реагировать.
Помещая потенциально проблемный код в блок try и следуя за ним одним или несколькими блоками catch, вы даёте программе чёткий путь управления исключительными ситуациями.
Если исключение не брошено, блок try выполняется нормально, а обработчики пропускаются.
В этом уроке вы узнаете:
- Что такое обработка исключений и зачем она нужна
- Ключевые слова:
throw,catch,try - Синтаксис и распространённые паттерны
- Стандартные исключения библиотеки C++
- Как создавать и использовать пользовательские исключения
Зачем нужна обработка исключений?
Она даёт существенные преимущества:
- Разделяет логику обработки ошибок от основного кода, улучшая читаемость и поддерживаемость.
- Позволяет функциям сообщать только о заботящих их исключениях; вызывающие могут обрабатывать остальные.
Ключевые слова обработки исключений
Три ключевых слова образуют основу:
- throw — сигнализирует об ошибке, создавая объект исключения.
- catch — перехватывает исключение и предоставляет код реакции.
- try — отмечает область кода, которая может бросить исключение.
Код внутри try называется защищённым; если он бросает исключение, выполняется соответствующий блок catch.
Синтаксис
try {
// защищённый код
} catch (Exception_Name exception1) {
// обработка exception1
} catch (Exception_Name exception2) {
// обработка exception2
}
// ... дополнительные catch-блоки
- Один
tryможет сопровождаться множествомcatch. - Тип в каждом
catchуказывает, какое исключение перехватывается. - Внутри
catchперехваченное исключение доступно по выбранному идентификатору.
Пример 1: Доступ к элементу vector за пределами диапазона
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec;
vec.push_back(0);
vec.push_back(1);
try {
vec.at(2); // за пределами диапазона
} catch (exception& ex) {
cout << "Exception occurred!" << endl;
}
return 0;
}
Вывод:

Скриншот кода:

Разбор кода:
- Подключаем
iostreamиvectorдля ввода/вывода и контейнеров. - Используем пространство имён
std. - Создаём
vector<int>и заполняем двумя элементами. - Пытаемся обратиться к элементу за границами внутри
try. - Перехватываем стандартное
std::exceptionи выводим сообщение. - Возвращаемся из
main.
Пример 2: Обработка деления на ноль
#include <iostream>
using namespace std;
double zeroDivision(int x, int y) {
if (y == 0) {
throw "Division by Zero!";
}
return static_cast<double>(x) / y;
}
int main() {
int a = 11, b = 0;
double c = 0;
try {
c = zeroDivision(a, b);
cout << c << endl;
} catch (const char* message) {
cerr << message << endl;
}
return 0;
}
Вывод:

Скриншот кода:

Разбор кода:
- Функция
zeroDivisionбросает C-строку при делении на ноль. - Вызов функции внутри
tryс выводом результата. - Перехват строкового исключения и вывод ошибки в
cerr.
Стандартные исключения C++

Стандартная библиотека объявляет богатую иерархию исключений в <exception>. Наиболее часто используемые:
| Исключение | Описание |
|---|---|
| std::exception | Базовый класс для всех стандартных исключений. |
| std::bad_alloc | Бросается new при нехватке памяти. |
| std::bad_cast | Бросается dynamic_cast при неудаче приведения. |
| std::bad_exception | Сигнализирует о неожиданном исключении. |
| std::bad_typeid | Бросается typeid для нулевого полиморфного glvalue. |
| std::logic_error | Ошибки, обнаруживаемые программистом. |
| std::domain_error | Недопустимый домен математической функции. |
| std::invalid_argument | Функция получила неверный аргумент. |
| std::length_error | Попытка создать слишком большую строку. |
| std::out_of_range | Бросается vector::at при индексе за пределами. |
| std::runtime_error | Ошибки времени выполнения, не попавшие в другие категории. |
| std::overflow_error | Математическое переполнение. |
| std::range_error | Значение вне диапазона для операции. |
| std::underflow_error | Математическое подтечение. |
Пользовательские исключения
Базовый класс std::exception можно расширить для создания доменно-специфичных типов ошибок. Переопределение what() даёт описательное сообщение.
Пример: пользовательское исключение
#include <iostream>
#include <exception>
using namespace std;
class NewException : public exception {
public:
const char* what() const noexcept override {
return "newException occurred";
}
} newex;
int main() {
try {
throw newex;
} catch (exception& ex) {
cout << ex.what() << '\n';
}
return 0;
}
Вывод:

Скриншот кода:

Разбор кода:
- Наследуем
NewExceptionотstd::exceptionи переопределяемwhat(). - Создаём объект
newexдля броска. - Бросаем
newexвнутриtry. - Перехватываем по ссылке к
std::exceptionи печатаем сообщение черезwhat().
Резюме
- Обработка исключений необходима для надёжных C++ приложений, восстанавливающихся после ошибок выполнения.
- Используйте
tryдля защиты кода,catchдля реакции,throwдля сигнализации проблем. - Используйте богатый набор стандартных исключений, расширяйте
std::exceptionдля кастомных типов ошибок. - Держите логику обработки ошибок отдельно от бизнес-логики для чистого, поддерживаемого кода.
Язык C
- Комментарии в C++: лучшие практики для читаемого и поддерживаемого кода
- Обработка исключений в Python: try, except, else и finally подробно
- Обработка исключений в Java: try, catch, finally, throw и throws
- Обработка исключений в Java: try-catch-finally и try-with-resources
- Оператор switch-case в C++: синтаксис, применение и практические примеры
- Динамическое выделение массивов в C++: практическое руководство с примерами кода
- Структуры (struct) в C++: объяснение с практическим примером
- Освоение std::list в C++: синтаксис, функции и практические примеры
- C++ Struct vs Class: ключевые отличия, синтаксис и лучшие сценарии использования
- 15 лучших IDE для C++ на Windows, macOS и Linux — бесплатные и платные (2021)