Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

<< temps[i].temperature << ")\n";

}

10.6. Обработка ошибок ввода-вывода

Вводя данные, мы должны предвидеть ошибки и обрабатывать их. Какими бывают ошибки? Как их обрабатывать? Ошибки возникают из-за того, что их совершают люди (неправильно поняли инструкцию, сделали опечатку, по клавиатуре прошлась кошка и т.д.), из-за того, что файлы не соответствуют спецификациям, из-за того, что программисты имеют неправильное представление об ожидаемых данных, и т.д. Возможности для совершения ошибок при вводе данных ничем не ограничены! Однако поток

istream
сводит их все к четырем возможным классам, которые называют состояниями потока (stream state)

К сожалению, различия между состояниями
fail
и
bad
определены неточно и зависят от точки зрения программистов на определение операций ввода-вывода для новых типов. Однако основная идея проста: если операция ввода обнаруживает простую ошибку форматирования, она позволяет потоку вызвать функцию
fail
, предполагая, что вы (пользователь операции ввода) способны ее исправить. Если же, с другой стороны, произошло нечто совершенно ужасное, например неправильное чтение с диска, то операция ввода позволяет потоку вызвать функцию
bad
, предполагая, что вам ничего не остается делать, кроме как отказаться от попытки считать данные из потока. Это приводит нас к следующей общей логике:

int i = 0;

cin >> i;

if (!cin) { // мы окажемся здесь (и только здесь),

// если операция ввода не выполнена

if (cin.bad) error("cin испорчен "); // поток поврежден: стоп!

if (cin.eof) {

// входных данных больше нет

// именно так мы хотели бы завершить ввод данных

}

if (cin.fail) { // с потоком что-то случилось

cin.clear; // приготовиться к дальнейшему вводу

// исправление ситуации

}

}

Выражение

!cin
можно прочитать как “поток
cin
в плохом состоянии”, или “с потоком
cin
что-то случилось”, или “поток
cin
не находится в состоянии
good
”. Это выражение противоположно по смыслу выражению “операция успешно завершена”. Обратите внимание на инструкцию
cin.clear
, в которой обрабатывается состояние
fail
. Если поток поврежден, то мы, вероятно, можем его восстановить. Для того чтобы сделать это, мы явно выводим поток из состояния
fail
и можем снова просматривать последовательность символов, находящихся в этом потоке; функция
clear
гарантирует, что после выполнения вызова
cin.clear
поток
cin
перейдет в состояние
good
.

Рассмотрим пример использования состояния потока. Представим себе, что считываем в вектор последовательность целых чисел, которые могут завершаться символом

*
или признаком конца файла (<Ctrl+Z> в системе Windows или <Ctrl+D> в системе Unix). Например, пусть в файле записаны следующие числа:

1 2 3 4 5 *

Ввести их можно с помощью такой функции:

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; // отлично: мы достигли конца файла

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
, который основывается на предположении, что поток помнит, какой символ был последним, и поэтому его не обязательно указывать явно.

  • Читать дальше
  • 1
  • ...
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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