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

  if (ist.bad) error("Поток ist поврежден."); // поток поврежден;

                                               // стоп!

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

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


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

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


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


void fill_vector(istream& ist, vector& 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

  }

}


Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже