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

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

    В таблице 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) >> х

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

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

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

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

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




Предыдущий шаг Содержание Следующий шаг