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
// считываем целые числа из потока 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
}
}