Почему выбрасывается исключение?

106
05 марта 2021, 03:50
#include <iostream>
#include <ctime>
#include <conio.h>
#include <string>
#define NOMINMAX
#include <limits>
#include <windows.h>
using namespace std;
void delay(double delaySec) {
    clock_t delayClock = delaySec * CLOCKS_PER_SEC;
    clock_t start = clock();
    while (clock() - start < delayClock);
}
int main() {
    setlocale(LC_ALL, "");
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    char ch;
    double delaySec;
    string phrase;
    cin.exceptions(istream::failbit | istream::badbit);
    do {
        cout << "Введите время задержки в секундах: ";
        try {
            cin >> delaySec;
        }
        catch (istream::failure exp) {
            cout << "Введите число!\n";
            cin >> delaySec;
        }
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout << "Введите фразу: ";
        getline(cin, phrase);
        delay(delaySec);
        cout << "Фраза: " << phrase << endl;
    } while (delaySec != 0);
    _getch();
    return 0;
}

Если ввести не число, то выводится строка "Введите число", а потом выбрасывается исключение в строке cin >> delaySec в блоке catch:

Возникло необработанное исключение по адресу 0x74EAAA12 в Delay2.exe: исключение Microsoft C++: std::ios_base::failure по адресу памяти 0x005BEB14

Почему это происходит и как это исправить?

Answer 1

Разумеется, выбрасывается.

  • Во-первых, когда в процессе первого cin >> delaySec возникла ошибка и в потоке cin выставился флаг failbit, сам по себе этот флаг сбрасываться не будет. Поток cin переходит в перманентное ошибочное состояние. Вывести его из этого состояния, т.е. очистить флаги ошибок, можете только вы явным образом, например через вызов cin.clear().

    Если поток находится в режиме выбрасывания исключений по каким-то флагам (как в вашем примере), то пока эти флаги не сброшены, все попытки чтения из данного потока будут мгновенно выбрасывать исключения, независимо от того, правильные данные вы подадите на вход или неправильные.

    Вы флаг failbit нигде не сбрасываете. Поэтому в вашем случае второй cin >> delaySec не будет даже пытаться ничего читать из потока, а вместо этого сразу же снова выбросит fail-исключение, которые вы не ловите. Его вы и видите.

  • Во-вторых, даже если вы сделаете cin.clear(), вам все равно еще нужно убрать из входного потока ошибочные входные данные. Если вы этого не сделаете, то вторая попытка cin >> delaySec будет пытаться читать все тот же неправильный вход. В результате опять произойдет та же самая ошибка и выбросится то же самое исключение.

    Я вижу, вы вставили в код чистку буфера от неправильного ввода

    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    

    но попытку повторного чтения cin >> delaySec вы делаете еще до чистки буфера. Должно быть наоборот: чистить буфер нужно до повторной попытки чтения. (А cin.clear() нужно сделать до cin.ignore().)

READ ALSO
Как на modx сделать отправку заявок через formIt

Как на modx сделать отправку заявок через formIt

Есть сайт, которую перенесли с Wordpress на ModXПосле чего форма отправки заявок перестала работать

128
Как создать блог с добовлением статей

Как создать блог с добовлением статей

Пытаюся создать простой блог не не как не могу добовлять статьи по сути готовая версия уже есть но нужно сделать это все одним классом во viespy...

102
Vk неправильно выводит информацию из meta og: тегов

Vk неправильно выводит информацию из meta og: тегов

Столкнулся проблемной, что vk при отправки ссылки главной страницы http://alisa-musicru/ отображает не заданный <meta property="og:title" content="Все песни Алисы...

216
Как отложить время до отправки формы

Как отложить время до отправки формы

На сайте есть форма для регистрацииПри нажатии на кнопку "Зарегистрироваться" должна быть анимация, но она не успевает проиграться, потому...

97