Ввод-вывод с использованием потоковых классов. Состояние потока данных и логические условия

   
На этом шаге мы рассмотрим способы определения состояния потока данных и связанные с ними логические условия.

   
В таблице 1 приведены две операторные функции, предназначенные для проверки состояния потоков данных в
логических выражениях.

Таблица 1. Потоковые операторы для логических выражений

Функция Описание
operator void*() роверяет нормальное состояние потока данных (эквивалент !fail())
operator! () Проверяет ошибочное состояние потока данных (эквивалент fail())

   
Оператор void*() обеспечивает короткую и наглядную запись проверки состояния потока данных в
управляющих структурах:

  // Пока стандартный поток ввода находится в нормальном состоянии... 
  while (std::cin) {
    .    .    .    .
  }

   
Проверка логических условий в управляющих структурах не требует прямого преобразования к bool. Достаточно
уникального преобразования к целому типу (например, int или char) или к типу указателя. Для чтения
объекта и проверки результата в одной команде часто требуется преобразование к void*:

  if (std::cin >> x) {
  // Чтение х выполнено успешно
  .    .    .    .
  }

   
Как уже было показано, следующее выражение возвращает cin:

  std::cin >> х

   
Следовательно, после чтения х команда эквивалентна такой команде:

  if (std::cin) {
    .    .    .    .
  }

   
Объект cin часто используется при проверке условий; оператор void* этого объекта возвращает
признак наличия ошибки потока данных.

   
Этот прием обычно применяется в циклах, выполняющих чтение и обработку объектов:

  // Пока удается прочитать obj 
  while (std::cin  >> obj) {
    // Обработка obj (в данном случае - простой вывод)
    std::cout << obj << std::endl;
  }

   
В этом фрагменте легко угадывается классический синтаксис фильтров С, примененный к объектам C++.
Цикл завершается при установке флага failbit или badbit. Эти флаги устанавливаются при
возникновении ошибки или достижении конца файла (попытка чтения за концом файла приводит к установке флага
eofbit или badbit). По умолчанию оператор >> игнорирует начальные пропуски. Обычно это
вполне устраивает программиста, но если obj относится к типу char, то пропуски могут оказаться
существенными. В этом случае в реализации фильтра можно использовать функции get() и put() потоковых
классов, а еще лучше - итератор istreambuf_iterator.

   
Оператор ! проверяет обратное условие. В соответствии со своим определением он возвращает true, если для
потока данных установлен бит failbit или badbit. Возможный вариант использования:

  if (! std::cin) {
    // Поток cin находится в ошибочном состоянии
    .    .    .    .
  }

   
Как и в случае с неявным преобразованием к логическому типу, этот оператор часто используется для совмещения
чтения с проверкой результата:

  it (! (std::cin >> x)) {
    // Попытка чтения завершилась неудачей
    .    .    .    .
  }

   
Следующее выражение возвращает объект cin, к которому применяется оператор !:

  ! std::cin  >> x

   
Выражение после оператора ! необходимо заключить в круглые скобки из-за относительного приоритета операторов;
без круглых скобок оператор ! будет выполнен первым. Другими словами, следующие два выражения эквивалентны:

  ! std::cin >> х 
  (!std::cin) >> х

   
Вряд ли это именно то, к чему стремился программист.

   
Хотя описываемые операторы очень удобны, следует обратить внимание на одну странность: двойное отрицание не
означает возвращения к исходному объекту:

  • cin - потоковый объект класса istream;
  • !!cin - логическая величина, описывающая состояние объекта cin.

   
Существует мнение, что преобразование к логическому значению не соответствует принципам хорошего стиля
программирования. Функции типа fail() обычно делают программу более понятной:

  std::cin >> х;
  it (std::cin.fail()) {
    .    .    .    .
  }

   
На следующем шаге мы рассмотрим состояние потока данных и исключения.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий