Чтение онлайн

на главную - закладки

Жанры

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

// об ошибке

ist.clear; // очищаем состояние потока

// и теперь снова можем искать признак

// завершения

char c;

ist>>c; // считываем символ, возможно, признак

// завершения

if (c != terminator) { // неожиданный символ

ist.unget; // возвращаем этот символ назад

ist.clear(ios_base::failbit); // переводим поток

// в состояние fail

}

}

}

Обратите

внимание на то, что пока мы не найдем признак конца файла, мы не выйдем из цикла. Кроме того, мы можем собрать некоторые данные, и функция, вызвавшая функцию
fill_vector
, может попытаться вывести поток из состояния
fail
. Поскольку мы очистили состояние, то, для того чтобы проверить символ, должны вернуть поток обратно в состояние
fail
. Для этого выполняется инструкция
ist.clear(ios_base::failbit)
. Обратите внимание на потенциально опасное использование функции
clear
: на самом деле функция
clear
с аргументом устанавливает указанные флаги (биты) состояния потока
iostream
, сбрасывая (только) не указанные. Переводя поток в состояние
fail
, мы указываем, что обнаружили ошибку форматирования, а не нечто более серьезное. Мы возвращаем символ обратно в поток
ist
, используя функцию
unget
; функция, вызывающая функцию
fill_vector
, может использовать его по своему усмотрению. Функция
unget
представляет собой более короткий вариант функции
putback
, который основывается на предположении, что поток помнит, какой символ был последним, и поэтому его не обязательно указывать явно.

Если вы вызвали функцию

fill_vector
и хотите знать, что вызвало прекращение ввода, то можно проверить состояния
fail
и
eof
. Кроме того, можно перехватить исключение
runtime_error
, сгенерированное функцией
error
, но понятно, что маловероятно получить больше данных из потока
istream
, находящегося в состоянии
bad
. Большинство вызывающих функций не предусматривает сложной обработки ошибок. По этой причине практически во всех случаях единственное, чего мы хотим сделать, обнаружив состояние
bad
, — сгенерировать исключение.

Для того чтобы облегчить себе жизнь, можем поручить потоку
istream
сделать это за нас.

// поток ist генерирует исключение, если попадает в состояние bad

ist.exceptions(ist.exceptions|ios_base::badbit);

Эти обозначения могут показаться странными, но результат простой: если поток

ist
окажется в состоянии
bad
, он сгенерирует стандартное библиотечное исключение
ios_base::failure
. Вызвать функцию
exceptions
можно только один раз. Все это позволяет упростить циклы ввода, игнорируя состояние
bad
.

void fill_vector(istream& ist, vector<int>& v, char terminator)

// считываем целые числа из потока ist в вектор v, пока не

// достигнем конца файла eof или признака завершения

{

int i = 0;

while (ist >> i) v.push_back(i);

if (ist.eof) return; // отлично: обнаружен конец файла

// не good, не bad и не eof,

// поток ist должен быть
переведен в состояние fail

ist.clear; // сбрасываем состояние потока

char c;

ist>>c; // считываем символ в поисках признака завершения ввода

if (c != terminator) { // Ох: это не признак завершения ввода,

// значит, нужно вызывать функцию fail

ist.unget; // может быть, вызывающая функция

// может использовать этот символ

ist.clear(ios_base::failbit); // установить состояние fail

}

}

Класс

ios_base
является частью потока
iostream
, в котором хранятся константы, такие как
badbit
, исключения, такие как
failure
, и другие полезные вещи. Для обращения к нему необходим оператор
::
, например
ios_base::badbit
(раздел B.7.2). Мы не планируем подробно описывать библиотеку
iostream;
для этого понадобился бы отдельный курс лекций. Например, потоки
iostream
могут обрабатывать разные наборы символов, реализовывать разные стратегии буферизации, а также содержат средства форматирования представлений денежных средств на разных языках (однажды мы даже получили сообщение об ошибке, связанной с форматированием представления украинской валюты). Все, что вам необходимо знать о потоках
iostream,
можно найти в книгах Страуструп (Stroustrup), The C++ Programming Language Страуструпа и Лангер (Langer), Standard C++ IOStreams and Locales.

Поток ostream имеет точно такие же состояния, как и поток

istream: good
,
fail
,
eof
и
bad
. Однако в таких программах, которые мы описываем в этой книге, ошибки при выводе встречаются намного реже, чем при вводе, поэтому мы редко их проверяем. Если вероятность того, что устройство вывода недоступно, переполнено или сломано, является значительной, то в программе следует предусмотреть проверку состояния потока вывода после каждой операции вывода, так как мы сделали выше по отношению к операции ввода.

10.7. Считывание отдельного значения

Итак, мы знаем, как считать последовательность значений, завершающихся признаком конца файла или завершения ввода. Впоследствии мы рассмотрим еще несколько примеров, а сейчас обсудим все еще популярную идею о том, чтобы несколько раз запрашивать значение, пока не будет введен его приемлемый вариант. Это позволит нам проверить несколько распространенных проектных решений. Мы обсудим эти альтернативы на примерах нескольких решений простой проблемы — как получить от пользователя приемлемое значение. Начнем с очевидного, но скучного и запутанного варианта под названием “сначала попытайся”, а затем станем его постепенно совершенствовать. Наше основное предположение заключается в том, что мы имеем дело с интерактивным вводом, в ходе которого человек набирает на клавиатуре входные данные и читает сообщения, поступающие от программы. Давайте предложим пользователю ввести целое число от 1 до 10 (включительно).

cout << "Пожалуйста, введите целое число от 1 до 10:\n";

int n = 0;

while (cin>>n) { // читаем

if (1<=n && n<=10) break; // проверяем диапазон

cout << "Извините " << n

<< " выходит за пределы интервала [1:10]; попробуйте еще \n";

}

Этот код довольно уродлив, но отчасти работоспособен. Если вы не любите использовать оператор

break
(раздел А.6), то можете объединить считывание и проверку диапазона.

Поделиться:
Популярные книги

Бастард Императора. Том 4

Орлов Андрей Юрьевич
4. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Бастард Императора. Том 4

Идеальный мир для Лекаря 6

Сапфир Олег
6. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 6

Мама из другого мира. Чужих детей не бывает

Рыжая Ехидна
Королевский приют имени графа Тадеуса Оберона
Фантастика:
фэнтези
8.79
рейтинг книги
Мама из другого мира. Чужих детей не бывает

Студент из прошлого тысячелетия

Еслер Андрей
2. Соприкосновение миров
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Студент из прошлого тысячелетия

Ну привет, заучка...

Зайцева Мария
Любовные романы:
эро литература
короткие любовные романы
8.30
рейтинг книги
Ну привет, заучка...

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9

Возвышение Меркурия. Книга 5

Кронос Александр
5. Меркурий
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 5

Её (мой) ребенок

Рам Янка
Любовные романы:
современные любовные романы
6.91
рейтинг книги
Её (мой) ребенок

(Бес) Предел

Юнина Наталья
Любовные романы:
современные любовные романы
6.75
рейтинг книги
(Бес) Предел

Курсант: Назад в СССР 11

Дамиров Рафаэль
11. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 11

Страж Кодекса. Книга III

Романов Илья Николаевич
3. КО: Страж Кодекса
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Страж Кодекса. Книга III

Паладин из прошлого тысячелетия

Еслер Андрей
1. Соприкосновение миров
Фантастика:
боевая фантастика
попаданцы
6.25
рейтинг книги
Паладин из прошлого тысячелетия

Леди Малиновой пустоши

Шах Ольга
Любовные романы:
любовно-фантастические романы
6.20
рейтинг книги
Леди Малиновой пустоши

Бастард Императора. Том 5

Орлов Андрей Юрьевич
5. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 5