Обработка исключений в C++: полное руководство
Исключение — проблема, возникающая во время выполнения программы. Исключение C++ — реакция на исключительную ситуацию во время работы программы, например попытку деления на ноль.
Исключения предоставляют способ передачи управления из одной части программы в другую. Обработка исключений в C++ строится на трёх ключевых словах: try, catch и throw.
throw — программа выбрасывает исключение при возникновении проблемы. Делается ключевым словом throw.
catch — программа перехватывает исключение обработчиком в месте, где нужно решить проблему. Ключевое слово catch указывает на перехват.
try — блок try выделяет код, для которого активируются определённые исключения. За ним следует один или несколько блоков catch.
Предполагая, что блок может выбросить исключение, метод перехватывает его комбинацией try и catch. Блок try/catch помещается вокруг кода, который может сгенерировать исключение. Код внутри try/catch называется защищённым кодом. Синтаксис:
try {
// защищённый код
} catch( ExceptionName e1 ) {
// блок catch
} catch( ExceptionName e2 ) {
// блок catch
} catch( ExceptionName eN ) {
// блок catch
}
Можно перечислить несколько catch для перехвата разных типов исключений, если try может выбросить больше одного типа в разных ситуациях.
Выбрасывание исключений
Исключения можно выбрасывать в любом месте блока кода с помощью оператора throw. Операнд throw определяет тип исключения и может быть любым выражением; тип результата выражения определяет тип выбрасываемого исключения.
Пример выбрасывания исключения при делении на ноль:
double division(int a, int b) {
if( b == 0 ) {
throw "Division by zero condition!";
}
return (a/b);
}
Перехват исключений
Блок catch после try перехватывает любое исключение. Можно указать тип исключения для перехвата — это определяется объявлением исключения в скобках после ключевого слова catch.
try {
// защищённый код
} catch( ExceptionName e ) {
// код обработки исключения ExceptionName
}
Этот код перехватит исключение типа ExceptionName. Если нужно, чтобы блок catch обрабатывал любой тип исключения, выбрасываемого в try, нужно поставить многоточие ... в скобках:
try {
// защищённый код
} catch(...) {
// код обработки любого исключения
}
Пример: выбрасывание исключения деления на ноль и его перехват:
Live Demo#include <iostream>
using namespace std;
double division(int a, int b) {
if( b == 0 ) {
throw "Division by zero condition!";
}
return (a/b);
}
int main() {
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
} catch (const char* msg) {
cerr << msg << endl;
}
return 0;
}
Так как мы выбрасываем исключение типа const char*, в блоке catch нужно использовать const char*. Результат:
Division by zero condition!
Стандартные исключения C++
C++ предоставляет список стандартных исключений, определённых в <exception>, которые можно использовать в программах. Они расположены в иерархии родитель-потомок:
Краткое описание каждого исключения:
| № | Исключение и описание |
|---|---|
| 1 | std::exception Базовый класс всех стандартных исключений C++. |
| 2 | std::bad_alloc Может быть выброшено оператором new. |
| 3 | std::bad_cast Может быть выброшено dynamic_cast. |
| 4 | std::bad_exception Полезно для обработки неожиданных исключений. |
| 5 | std::bad_typeid Может быть выброшено typeid. |
| 6 | std::logic_error Исключение, которое теоретически можно обнаружить чтением кода. |
| 7 | std::domain_error Выбрасывается при использовании математически недопустимой области определения. |
| 8 | std::invalid_argument Выбрасывается из-за недопустимых аргументов. |
| 9 | std::length_error Выбрасывается при создании слишком большого |
| 10 | std::out_of_range Может быть выброшено методом |
| 11 | std::runtime_error Исключение, которое теоретически нельзя обнаружить чтением кода. |
| 12 | std::overflow_error Выбрасывается при математическом переполнении. |
| 13 | std::range_error Возникает при попытке сохранить значение вне диапазона. |
| 14 | std::underflow_error Выбрасывается при математическом недотеке (underflow). |
Определение собственных исключений
Можно определить свои исключения, наследуясь и переопределяя функциональность класса exception. Пример использования std::exception для реализации собственного исключения стандартным способом:
#include <iostream>
#include <exception>
using namespace std;
struct MyException : public exception {
const char * what() const throw() {
return "C++ Exception";
}
};
int main() {
try {
throw MyException();
} catch(MyException& e) {
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
} catch(std::exception& e) {
// другие ошибки
}
}
Результат:
MyException caught C++ Exception
Здесь what() — публичный метод класса exception, переопределённый всеми дочерними классами исключений. Он возвращает причину исключения.
Язык C
- Освоение операторов C++: полное руководство с практическими примерами
- Комментарии в C++: лучшие практики для читаемого и поддерживаемого кода
- Шаблоны классов в C++: практическое руководство
- Работа с файлами в C: мастерство ввода-вывода с fopen, fprintf, fread и fseek
- Обработка исключений в Java: try, catch, finally, throw и throws
- Обработка исключений в C++: практические примеры try, catch, throw
- Мастерство обработки исключений в Python: эффективное использование try, except, finally и raise
- Обработка ошибок в C: лучшие практики и техники
- Язык программирования C++: обзор и ключевые особенности
- Константы и литералы в C++: типы, синтаксис и лучшие практики