Литмир - Электронная Библиотека
A
A

                                               // стоп!

  if (ist.fail()) { // очищаем путаницу как можем и сообщаем

                    // об ошибке

    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()
, — сгенерировать исключение.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Для того чтобы облегчить себе жизнь, можем поручить потоку
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.

143
{"b":"847443","o":1}