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

int main()

{

  cout << "Пожалуйста, введите имя файла для ввода: ";

  string name;

  cin >> name;

  ifstream ist(name.c_str()); // поток ist считывает данные

                              // из файла,

                              // имя которого задано строкой name

  if (!ist) error("Невозможно открыть файл для ввода ",name);

  cout << "Пожалуйста, введите имя файла для вывода: ";

  cin >> name;

  ofstream ost(name.c_str()); // поток ost записывает данные

                              // в файл, имя которого задано

                              // строкой name

  if (!ost) error("Невозможно открыть файл для вывода ",name);

  vector<Reading> temps;      // здесь хранится считанная информация

  int hour;

  double temperature;

  while (ist >> hour >> temperature) {

    if (hour < 0 || 23 <hour) error("Некорректное время");

    temps.push_back(Reading(hour,temperature));

  }

  for (int i=0; i<temps.size(); ++i)

    ost << '(' << temps[i].hour << ','

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

}

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

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

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

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

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 К сожалению, различия между состояниями
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&amp; ist, vector&lt;int&gt;&amp; v, char terminator)

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

  // пока не будет достигнут признак eof() или символ завершения

{

  int i = 0;

  while (ist &gt;&gt; i) v.push_back(i);

  if (ist.eof()) return; // отлично: мы достигли конца файла

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

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