В книге Бьярна Страуструпа Принципы и практика программирования с использованием C ++ (шестой выпуск, ноябрь 2012 г.) , if (cin) и if (!cin) вводятся на стр. 148 и серьезно используются на стр. 178. while (cin) вводится на стр. 183 и серьезно используется на стр. 201.

Однако мне кажется, что я не совсем понимаю, как работают эти конструкции, поэтому я их исследую.

Если я скомпилирую и запустил это:

int main()
{
        int i = 0 ;
        while (cin) {
                cout << "> ";
                cin >> i ;
                cout << i << '\n';
        }
}

Я получаю что-то вроде:

$ ./spike_001
> 42
42
> foo
0
$
  • Почему при вводе "foo" для i устанавливается значение 0?
  • Почему при вводе "foo" cin устанавливается на false?

В качестве альтернативы, если я запустил и скомпилирую это:

int main()
{
        int i = 0 ;
        while (true) {
                cout << "> ";
                cin >> i ;
                cout << i << '\n';
        }
}

Я получаю что-то вроде:

$ ./spike_001
> 42
42
> foo
> 0
> 0
...

Последняя часть пользовательского ввода здесь - foo. После этого строка > 0 повторно выводится программой на стандартный вывод, пока не будет остановлена ​​с помощью Ctrl + C.

  • Опять же, почему при вводе "foo" для i устанавливается значение 0?
  • Почему пользователю не предлагается ввести новое значение для i на следующей итерации цикла while после ввода foo?

Это использует g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3.

Прошу прощения за такой длинный вопрос, но я думаю, что все сводится к следующему: «Как оценивается cin?»

c++
0
user82216 12 Мар 2014 в 02:58
Вам нужно проверить флаги ошибок. Проблема в том, что вы пытаетесь передать строку "foo" в целое число i. cin обычно выполняет преобразования типов, необходимые при использовании оператора >>, но нет способа преобразовать "foo" в целое число.
 – 
Red Alert
12 Мар 2014 в 03:02
Возможно, это полезно: stackoverflow.com/questions /17928865/…
 – 
Bill Lynch
12 Мар 2014 в 03:02

2 ответа

Лучший ответ

Что ж, std::cin (или, точнее, std::basic_ios ) имеет operator bool для неявного преобразования std::cin в bool по запросу (например, в вашей оценке if).

Семантика следующая:

Проверяет, нет ли в потоке ошибок. Возвращает true, если поток не содержит ошибок и готов к операциям ввода-вывода. В частности, возвращает !fail().


Почему при вводе "foo", по-видимому, i устанавливается в 0?

Опять же, почему ввод "foo", по-видимому, приводит к тому, что i устанавливается в 0?

Поскольку operator>> в int ожидает целое число в строке.

Из cppreference:

Если извлечение не удается (например, если была введена буква, где ожидается цифра), значение остается неизменным, и бит сбоя устанавливается.


Почему при вводе «foo» для cin устанавливается значение false?

Поскольку бит ошибки установлен, поэтому fail() возвращает true.


Почему пользователю не предлагается ввести новое значение для i на следующей итерации цикла while после ввода foo?

Это потому, что std::cin имеет установленный бит ошибки, поэтому он не может получить ввод и просто печатает старое значение i, которое равно 0.

1
Community 20 Июн 2020 в 12:12
Спасибо :) Вы говорите: «Если извлечение не удается (например, если вместо цифры была введена буква), значение остается без изменений...» Но значение не остается без изменений: оно вместо этого изменено с (например) 42 на 0.
 – 
user82216
12 Мар 2014 в 03:15
А, на странице cppreference, на которую вы ссылаетесь, я вижу, что "с тех пор C++11", "Если извлечение не удается, в значение записывается ноль и устанавливается бит ошибки." Итак, я предполагаю, что компилятор по умолчанию использует С++ 11 :)
 – 
user82216
12 Мар 2014 в 03:21
@sampablokuper, если вы сомневаетесь в стандартной библиотеке, просто обратитесь к cppreference. Это хороший источник. :)
 – 
Shoe
12 Мар 2014 в 03:32

Когда вы используете оператор >> в потоке, он пытается извлечь значение этого типа из строки. Другими словами, когда вы выполняете cin >> i, где i - это int, поток пытается извлечь int из потока. Если это удается, i устанавливается на извлеченное значение, и все в порядке. Если это не удается, устанавливается badbit потока. Это важно, потому что обработка потока как bool эквивалентна проверке, установлен ли он badbit (if (cin) похож на if (cin.good())).

Так или иначе ... что происходит, так это то, что foo устанавливает плохой бит, поскольку извлечение не удается. На самом деле, вы должны проверить, успешно ли извлекается напрямую:

if (cin >> i) { /* success */ }

Что касается качества кода, я подозреваю, что вы используете using namespace std;. Помните, что это может быть опасным.

1
Community 23 Май 2017 в 13:33
Спасибо. if (cin >> i) уже имел интуитивно понятный для меня смысл, но хотя Страуструп использует его в некоторых случаях, это не то, что он использует в своих примерах на страницах, которые я упомянул. Поскольку я хочу понять все примеры, это означает, что мне также нужно понимать if (cin) и while (cin).
 – 
user82216
12 Мар 2014 в 03:07
Если это имеет смысл, operator>> в потоках фактически возвращает себя. Таким образом, возврат cin >> i равен cin. Это то, что позволяет выполнять неявное логическое преобразование и позволяет создавать более сложные цепочки, такие как cin >> i >> s >> f >> ....
 – 
Corbin
12 Мар 2014 в 03:09