Бьерн Страуструп - Язык программирования С++. Главы 9-10
Страница 25. Состояния потока



10.3.2 Состояния потока

С каждым потоком (istream или ostream) связано определенное состояние.
Нестандартные ситуации и ошибки обрабатываются с помощью проверки и
установки состояния подходящим образом.
Узнать состояние потока можно с помощью операций над классом ios:

     class ios { //ios является базовым для ostream и istream
         //...
     public:
         int eof() const;     // дошли до конца файла
         int fail() const;    // следующая операция будет неудачна
         int bad() const;     // поток испорчен
         int good() const;    // следующая операция будет успешной
         //...
     };

Последняя операция ввода считается успешной, если состояние задается
good() или eof(). Если состояние задается good(), то последующая
операция ввода может быть успешной, в противном случае она будет
неудачной. Применение операции ввода к потоку в состоянии, задаваемом
не good(), считается пустой операцией. Если произошла неудача при
попытке чтения в переменную v, то значение v не изменилось (оно не
изменится, если v имеет тип, управляемый функциями члена из istream
или ostream). Различие между состояниями, задаваемыми как fail() или
как bad() уловить трудно, и оно имеет смысл только для разработчиков
операций ввода. Если состояние есть fail(), то считается, что поток
не поврежден, и никакие символы не пропали; о состоянии bad() ничего
сказать нельзя.
    Значения, обозначающие эти состояния, определены в классе ios:

     class ios {
         //...
     public:
         enum io_state {
             goodbit=0,
             eofbit=1,
             filebit=2,
             badbit=4,
         };
         //...
     };

Истинные значения состояний зависят от реализации, и указанные значения
приведены только, чтобы избежать синтаксически неправильных конструкций.
 Проверять состояние потока можно следующим образом:

     switch (cin.rdstate()) {
     case ios::goodbit:
         // последняя операция с cin была успешной
         break;
     case ios::eofbit:
         // в конце файла
         break;
      case ios::filebit:
         // некоторый анализ ошибки
         // возможно неплохой
         break;
       case ios::badbit:
         //  cin возможно испорчен
         break;
       }

В более ранних реализациях для значений состояний использовались
глобальные имена. Это приводило к нежелательному засорению
пространства именования, поэтому новые имена доступны только в пределах
класса ios. Если вам необходимо использовать старые имена в сочетании с
новой библиотекой, можно воспользоваться следующими определениями:

     const int _good = ios::goodbit;
     const int _bad = ios::badbit;
     const int _file = ios::filebit;
     const int _eof = ios::eofbit;

     typedef ios::io_state state_value ;

Разработчики библиотек должны заботится о том, чтобы не добавлять
новых имен к глобальному пространству именования. Если элементы
перечисления входят в общий интерфейс библиотеки, они всегда
должны использоваться в классе с префиксами, например, как ios::goodbit
и ios::io_state.
      Для переменной любого типа, для которого определены операции
<< и >>, цикл копирования записывается следующим образом:

      while (cin>>z) cout << z << '\n';

Если поток появляется в условии, то проверяется состояние потока, и
условие выполняется (т.е. результат его не 0) только для состояния
good(). Как раз в приведенном выше цикле проверяется состояние потока
istream, что является результатом операции cin>>z. Чтобы узнать,
почему произошла неудача в цикле или условии, надо проверить состояние.
Такая проверка для потока реализуется с помощью операции
приведения (7.3.2).
   Так, если z является символьным вектором, то в приведенном цикле
читается стандартный ввод и выдается для каждой строки стандартного
вывода по одному слову (т.е. последовательности символов, не являющихся
обобщенными пробелами). Если z имеет тип complex, то в этом цикле
с помощью операций, определенных в 10.2.2 и 10.2.3, будут копироваться
комплексные числа. Шаблонную функцию копирования для потоков со
значениями произвольного типа можно написать следующим образом:

     complex z;
     iocopy(z,cin,cout);    // копирование complex

     double d;
     iocopy(d,cin,cout);    // копирование double
     char c;
     iocopy(c,cin,cout);    // копирование char

    Поскольку надоедает проверять на корректность каждую операцию ввода-
вывода, то распространенным источником ошибок являются именно те места в
программе, где такой контроль существенен. Обычно операции вывода не
проверяют, но иногда они могут завершиться неудачно. Потоковый ввод-
вывод разрабатывался из того принципа, чтобы сделать исключительные
ситуации легкодоступными, и тем самым упростить обработку ошибок
в процессе ввода-вывода.

 
« Предыдущая статья   Следующая статья »