Основы программирования на С++ для начинающих

Исключения в С++

Иногда, во время работы программ, встречаются ситуации которые препятствуют дальнейшей нормальной их работе. К примеру при делении числа на ноль, программа завершит работу не смотря на то, сколько пользователь работал в программе, и какой объем данных внес. Программа просто закроется.

И представьте, если до этого пользователь вносил в программу данные несколько часов и проводил расчеты. При таком аварийном закрытии программы все эти данные и расчеты пропадут. Согласитесь – не очень приятно. Также может встретиться такая ситуация, когда программа пытается открыть недоступный в этот момент файл, или запросить больше, чем доступно памяти.

Такого рода ситуации программистам надо стараться предвидеть и строить программы так, чтобы они могли гибко реагировать, а не аварийно закрываться. В моей любимой книге Язык программирования C++. Лекции и упражнения автора С. Прата, дано следующее определение исключениям в С++:

исключения в с++, исключения c++, программирования для начинающих

Чтобы вам не сложно было понять механизм работы исключений в С++, рассмотрим их на простом примере. В нем мы предвидим тот случай, что в какой-то момент в ходе расчетов программы, может встретиться деление числа на 0. Наберите и скомпилируйте код, расположенный ниже. Чтобы убедиться в том, как реагирует программа на такую ситуацию, внесите число 0 в переменную num2 (она выступает делителем в примере).

Так как переменная var равна 3, цикл while, в нормальной ситуации, должен отработать три раза. С каждым шагом цикла var уменьшается на единицу с помощью декремента. Но так как мы сразу внесли значение 0 в переменную num2, программа не пройдет до конца даже первый шаг цикла. Она прервется.

В следующем листинге, мы исправим это упущение – добавим несколько компонентов, которые помогут среагировать на данную ситуацию без прерывания работы программы. А именно:

    • блок try или try-блок  (попытка, проба);

 

    • генератор исключения  – блок throw (обработать, запустить);

 

  • обработчик исключения, который его  перехватывает -команда catch (поймать, ловить)

Как работает исключение? – Программист прописывает в коде (в try-блоке) конкретное условие, что если переменная num2 станет равна 0, то в таком случае необходимо генерировать исключение в throw. Далее, то что сгенерировал throw, перехватывает  catch-блок (в виде параметра функции) и программа выполнит тот код, который прописан в этом блоке.

Пример:

Разберем подробно. В строках 21-29 находится блок try. В нем необходимо размещать тот код, который может привести к необратимым ошибкам. Еще до арифметического выражения деления задаем условие: если num2 будет равно 0, то пусть throw генерирует число 999 (к примеру).

В том случае, сразу после генерации числа, дальнейшие команды в блоке  try выполняться уже не будут, а само число “упадет” в блок catch (в виде параметра). Далее выполнится то, что указано в блоке catch – в нашем случае, это будет сообщение об ошибке:

cout << "Ошибка №" << thr << " - деление на 0!!!" << endl;

и программа будет выполнять последующие команды. В том случае, если число num2 != 0, то throw ничего не генерирует и catch-блок не сработает.

Посмотрите теперь, как отреагирует программа, если вы введете num2 равное нулю. Запускайте программу.

исключения в с++, исключения c++, программирования для начинающих

Как видим, там где могла произойти ошибка и досрочное завершение программы, мы увидели сообщение Ошибка №999 – деление на 0!!!   Программа “перескочила” через операцию деления на 0 и выполнила  catch-блок.

Чтобы вы лучше поняли, как значение генерируемое throw перехватывает catch-блок, замените код в строках 21 – 33 на этот:

В этом примере, если num2 равно 0, throw генерирует строку, а не число. Строка “падает” в catch-блок и выводится на экран.

Рассмотрим еще такой пример, когда исключение генерируется в функции, которая делит одно число на другое:

Чтобы исключение сработало правильно, эту функцию надо вызвать в блоке try:

catch перехватит число 99, а деление на 0 не состоится.

Основное, что нужно запомнить об исключениях в С++:

    • В try-блоке (блоке повторных попыток) необходимо размещать код, который потенциально может привести к аварийному закрытию программы;

 

    • Исключение генерируется в блоке throw. Если throw сработает программа автоматически приступит к выполнению команд catch-блока, игнорируя оставшийся код в try-блоке;

 

    • Улавливающий блок – catch-блок, перехватывает то, что генерирует блок throw. Он обязательно должен находиться под  try-блоком. Ничего не должно быть прописано между ними;

 

  • catch-блок не сработает, если исключение не было сгенерировано. Программа его просто проигнорирует.

9 thoughts on “Исключения в С++

  1. Вообще то, тема исключений в любом языке программирования – достаточно скользкая. Такой механизм вносит как свои преимущества, так и свои недостатки и скрытые опасности использования.
    Язык C++ – производный от C, и в это развитие включили исключения. Следующее развитие (2008-2009г.г.) языка C – это язык Go. Из него исключения были разработчиками исключены и с очень обстоятельной опубликованной аргументацией почему они это сделали.
    Реюме: исключения в C++ нужно использовать, но только там, где они крайне необходимы, где без них нельзя обойтись. В остальных случаях лучше использовать традиционный возврат кода ошибки.

  2. Помогите люди добрые!!! Что неправильно с try у меня?

    #include
    #include
    #include // содержит time()
    using namespace std;

    int main()
    {
    setlocale(LC_ALL, "rus");

    int s1 = 0;
    int s2 = 0;
    char exit = 1;
    int over = 0;

    cout <<
    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
    cout << " Делите только у нас !!! \n";
    cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
    do
    {
    cout << "\n ~~~~~~~~~~ Введите ваши числа: ~~~~~~~~~~ \n";
    cout < ";
    cin >> s1;
    cout < ";
    cin >> s2;
    try
    {
    over = s1 / s2;
    cout < " << over << endl;
    cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
    cout << " Для продолжения вычислений нажми - 1, Для выхода - 0 \n";
    cout << exit;
    throw 999;
    }
    catch (int thr)
    {
    cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
    cout << " ~~~~~~~~ Похоже ты допустил ошибку!!! ~~~~~~~~ ";
    cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
    }
    } while (exit != 0);
    return 0;
    }

    1. А у вас до throw дело не доходит – аварийное завершение наступает раньше, при делении на 0.

      И параметром catch должно быть что-то, наследуемое от класса исключений:
      catch( exception const& e ) {

  3. Здравствуйте. У вас ошибка в третьем листинге.

    cout << num1 / num2 << endl; //нужно вывести за пределы оператора if. иначе не работает.

  4. Онлайн компилятор вообще не компилирует код с “try” и т.д. … – показывает ошибку

    1. 1). Нужно указывать КАКОЙ онлайн компилятор – их много, и есть совсем с придурью…
      2). В разных стандартах C++ (например C++11) синтаксис записи блока try {} catch – может отличаться;
      3). Многие онлайн компиляторы (лучшие) позволяют указать тот стандарт языка C++, который будет использоваться в коде;

  5. Для тех у кого не работает код выше, используйте этот:

    #include
    using namespace std;
    int main()
    {
    setlocale(LC_ALL, “rus”);

    int num1;
    int num2;

    int var = 3;
    while (var != 0)
    {
    cout <> num1;
    cout <> num2;

    cout << "num1 + num2 = " << num1 + num2 << endl;
    cout << "num1 / num2 = ";

    try // тут располагается код, который потенциально может вызвать ошибку
    {
    if (num2 == 0)
    {
    throw 999; // генерировать целое число 999
    }
    cout << num1 / num2 << endl;
    }

    catch (int thr)// сюда передастся число, которое сгенерировал throw
    {
    cout << "Ошибка №" << thr << " – деление на 0!!!" << endl;
    }

    cout << "num1 – num2 = " << num1 – num2 << endl;
    cout << "=================================" << endl << endl;

    var–;
    }

    cout << "Программа завершила работу!" << endl << endl;

    return 0;
    }

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *