При выполнении кода на C++ могут возникать разные ошибки, которые не позволяют программе выполнять свою работу. Для работы с ошибками или исключениями в C++ используются ключевые слова try
, catch
и throw
.
Содержание статьи:
1. Вступление: виды исключений и знакомство с try, catch и throw в C++
2. Генерируем исключения в C++
4. Обрабатываем ошибки с try и catch in С++
5. Как работают throw, try и catch в C++: примеры
6. Еще немного о порядке обработке ошибок в C++
Есть два вида исключений, с которыми вы можете столкнуться в процессе:
Когда происходит какое-то событие, прерывающее нормальное функционирование программы, C ++ обычно останавливается и выдает сообщение об ошибке. Когда это происходит, говорят, что C++ выбрасывает ошибку — throw an exception. Мы уже упоминали, что для работы с ошибками или исключениями в C++ используются определенные ключевые слова, давайте познакомимся с ними поближе:
try
: позволяет определить блок кода, который будет проверяться на наличие ошибок во время его выполнения;throw
: нужен для создания и отображения исключений и используется для перечисления ошибок, которые генерирует функция, но не может самостоятельно обрабатывать исключения;catch
— блок кода, который выполняется при возникновении определенного исключения в блоке try
.Давайте посмотрим, как выглядит пример кода в С++ с использованием try
catch
и throw
:
try { int age = 15; if (age >= 18) { cout << "Access granted - you are old enough."; } else { throw (age); } } catch (int myNum) { cout << "Access denied - You must be at least 18 years old.\n"; cout << "Age is: " << myNum; }
Вкратце объясним, как работают операторы try
и catch
в С++ на примере этого блока. Мы используем блок try
для тестирования определенных строк кода: если переменная age
меньше 18, мы генерируем исключение и обрабатываем его в блоке catch
.
С помощью catch
мы перехватываем ошибку и прописываем способ ее обработки. Оператор принимает параметр: в примере используется переменная типа int myNum
для вывода значения возраста.
Если все данные соответствуют установленным параметрам, то ошибки не возникает. Например, если указанный возраст будет больше 18, а не 15, как указано в примере, то блок catch
просто пропускается.
Если ошибка присутствует, то оператор throw
выбросит ошибку. В throw
можно прописать любое значение и оператор может выдать текст с пояснением, например:
Access denied - You must be at least 18 years old. Age is: 15
Или установить числовое значение, например, то код ошибки будет выглядеть следующим образом:
Access denied - You must be at least 18 years old. Error number: 505
После такой большой вводной части подробно рассмотрим генерацию исключений и как их обрабатывать, примеры использования try
и catch
в С++, подробно расскажем про задачи операторов.
Исключения могут быть выброшены в любом месте кода. Для этого в блоке нужно прописать throw
.
Этот оператор определяет тип исключения и может быть любым выражением. Также throw
сигнализирует об ошибке в коде и выводит исключение в консоль.
Помимо использования оператора throw
, есть еще один способ мониторить ошибки в коде. Он более традиционный, но давайте рассмотрим и его, чтобы лучше понять механику обработки ошибок с помощью операторов.
Обычно мы разбиваем программу на несколько функций или подпрограмм, чтобы сделать ее читабельной и простой для понимания. Получается, что программа будет иметь связанные вызовы функций. То есть одна функция использует ту информацию, которую ей предоставляет другая функция.
Здесь возникают основные проблемы с обработкой ошибок при использовании оператора if
:
Вот так выглядит обработка ошибок в коде при использовании оператора if
:
unsigned int error_type = 0; int add(int a, int b) { if (a > 100 || b > 100) { error_type = 1; return -1; } else if (a < 0 || b < 0) { error_type = 2; return -1; } return a + b; } int add_wrapper(int a, int b) { return add(a, b); } int main(int, char**) { if (add_wrapper(-1, 8) < 0) { if (error_type == 1) { std::cout << "add operation failed. parameters must be <= 100" << "\n"; } else { std::cout << "add operation failed. parameters must be >= 0" << "\n"; } } else { std::cout << "add operation succeeded" << "\n"; } return 0; }
А вот так будет выглядеть код с использованием try
и catch
в С++ (example):
#include <iostream> using namespace std; class Test { public: Test() { cout << "Constructor of Test " << endl; } ~Test() { cout << "Destructor of Test " << endl; } }; int main() { try { Test t1; throw 10; } catch (int i) { cout << "Caught " << i << endl; } }
По сравнению с несколькими строками кода в случае try
и catch
в С++, предыдущий блок выглядит очень перегруженным и длинным. В целом при использовании оператора if
обработка ошибок и программный код тесно взаимосвязаны. Из-за этого код становится беспорядочным, и трудно гарантировать, что все ошибки будут обработаны и программа будет работать нормально.
Метод try
/catch
, в свою очередь, обеспечивает четкое разделение между кодом, который знает об ошибке, и кодом, который знает, как обрабатывать ошибку. Таким образом, код, который находятся между этими операторами, может безопасно игнорировать ошибку.
Поэтому, запуская код в С++ Builder, лучше искать исключения с помощью try
, catch
и throw
. Это сделает ваш код проще, чище и с меньшей вероятностью вы допустите ошибки в программе.
Для того чтобы проверить блок кода на ошибки и аномалии, используется оператор try
. Так мы можем быть уверены, что если появится исключение в этой части кода, то try
его заметит. Главная особенность оператора в том, что в отличие от if
/ else
, которые смешиваются с обычным потоком данных, try
отделяет обработку ошибок от обычного течения программы.
Блок try
помещается вокруг кода, который может генерировать исключение, и закрывается другим оператором этой пары — catch
. Код в блоке try
/ catch
называется защищенным кодом, а синтаксис для использования связки этих операторов выглядит следующим образом:
try { // protected code } catch( ExceptionName e1 ) { // catch block } catch( ExceptionName e2 ) { // catch block } catch( ExceptionName eN ) { // catch block }
С помощью метода try
/ catch
можно перечислить и поймать сразу несколько видов исключений, если блок try
вызывает несколько типов ошибок в разных ситуациях. Несмотря на то, что функция может генерировать множество исключений, вы можете обрабатывать не все, а только некоторые из них.
Блок catch
, идущий в паре с оператором try
, ловит и обрабатывает исключения. Чтобы указать, какой тип исключения вы хотите поймать и обработать, нужно прописать это в скобках после ключевого слова catch
:
try { // protected code } catch( ExceptionName e ) { // code to handle ExceptionName exception }
Приведенный выше код перехватит только исключение типа ExceptionName
. Если вы хотите указать, что блок catch
должен обрабатывать любой тип ошибок, который находит оператор try
, просто поместите многоточие ...
между скобками:
try { // protected code } catch(...) { // code to handle any exception }
Рассмотрим пример кода, в котором генерируется исключение деления на ноль:
#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 *
, чтобы ошибку можно было определить и обработать. Если скомпилировать и запустить этот блок кода, то в результате получим условие прописанное в throw
:
Division by zero condition!
Рассмотрим на примерах, как между собой взаимодействуют операторы throw
, try
и catch
в С++. В блоке кода ниже приведен простой пример, демонстрирующий обработку исключений. Результат программы наглядно покажет, в какой последовательности происходит выполнение операторов:
#include <iostream> using namespace std; int main() { int x = -1; // Some code cout << "Before try \n"; try { cout << "Inside try \n"; if (x < 0) { throw x; cout << "After throw (Never executed) \n"; } } catch (int x ) { cout << "Exception Caught \n"; } cout << "After catch (Will be executed) \n"; return 0; }
В результате получается следующая последовательность:
Before try Inside try Exception Caught After catch (Will be executed)
Нужно не забывать прописывать одинаковые типы исключений в try
/ catch
. Если исключение одного типа будет выброшено, а catch
не сможет его поймать и обработать, то программа завершается ненормально:
#include <iostream> using namespace std; int main() { try { throw 'a'; } catch (int x) { cout << "Caught "; } return 0; }
В этом примере кода исключение является символом, но блок catch
для захвата символа отсутствует. В результате блок вернет нам не исключение, а вот такое предупреждение:
terminate called after throwing an instance of 'char' This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
С помощью try
/ catch
можно указывать кастомные типы исключений, наследуя и переопределяя функциональность класса исключений. В примере ниже приведем код, который покажет, как вы можете использовать класс 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) { //Other errors } }
Результат выполнения кода выглядит так:
MyException caught C++ Exception
Когда мы прописываем операторы try
/ catch
в коде, то исключение выбрасывается только при исполнении определенных условий. Рассмотрим как работают try
, catch
и throw
в С++ на примере:
#include <cmath> // for sqrt() function #include <iostream> int main() { std::cout << "Enter a number: "; double x {}; std::cin >> x; try // Ищет исключения в блоке и направляет их к обработчику catch { // этот блок сработает, если пользователь ввел отрицательное число if (x < 0.0) throw "Can not take sqrt of negative number"; // throw выбрасывает исключение типа const char* // Если пользователь ввел число больше 0, то выполняется этот блок кода std::cout << "The sqrt of " << x << " is " << std::sqrt(x) << '\n'; } catch (const char* exception) // обработчик исключений типа const char* { std::cerr << "Error: " << exception << '\n'; } }
Пользователь может ввести число больше нуля, как и задумано. Тогда программа просто продолжит работать в нормальном режиме и пропустит блок с оператором catch
. Допустим, пользователь ввел число 49. Тогда результат выполнения кода будет следующим:
Enter a number: 49 The sqrt of 49 is 7
Но пользователи не всегда действуют так, как задумывал разработчик. Поэтому оператор catch
нужен нам для того, чтобы программа не сломалась от непредвиденных значений, а могла нормально функционировать и дальше. Поэтому если пользователь введет число меньше нуля, то после того, как try
обнаружит непредусмотренное значение, заработают операторы catch
и throw
, и программа выдаст такое значение:
Enter a number: -4 Error: Can not take sqrt of negative number
Таким образом, строки кода с catch
и throw
выполняются только тогда, когда try
обнаруживает исключение в коде. Если все данные удовлетворяют условиям кода, то блок с исключениями просто пропускается программой.
Как использовать try
, catch
и throw
в С++, мы разобрались. Теперь кратко напомним, зачем все это нужно:
try
/ catch
занимает меньше строк и легче читается. Блоков с операторами if
/ else
может быть очень много и они будут повторяться, тогда как try
/ catch
содержит только два блока. Видео: С++ try catch. Обработка исключений С++. Try catch: что это. Изучение С++ для начинающих
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…