На этом шаге мы рассмотрим использование функций для работы с состоянием потока данных.
В таблице 1 перечислены функции для работы с текущим состоянием потока данных.
Функция | Описание |
---|---|
good() | Возвращает true, если поток данных находится в нормальном состоянии (то есть при установке флага goodbit) |
eof() | Возвращает true при обнаружении признака конца файла (установка флага eofbit) |
fail() | Возвращает true при обнаружении ошибки (установка флага failbit или badbit) |
bad() | Возвращает true при обнаружении фатальной ошибки (установка флага badbit) |
rdstate() | Возвращает установленные флаги |
clear() | Сбрасывает все флаги |
clear(state) | Сбрасывает все флаги и устанавливает флаги, содержащиеся в state |
setstate(state) | Устанавливает флаги, содержащиеся в state |
Первые четыре функции проверяют состояние отдельных флагов и возвращают логическую величину. Учтите, что функция fail() возвращает true при установке как failbit, так и badbit. Хотя такое поведение объясняется в основном историческими причинами, у него есть определенные достоинства - для выявления ошибки достаточно проверить всего одно условие.
Также существуют более общие функции для проверки и изменения состояния флагов. При вызове функции clear() без параметров сбрасываются все флаги ошибок (в том числе и eofbit):
// Сброс всех флагов ошибок (включая eofbit)
strm.clear();
Если функция clear() вызывается с передачей параметра, то состояние потока данных изменяется в соответствии с переданным значением; переданные флаги устанавливаются для потока данных, а остальные флаги сбрасываются. У этого правила есть единственное исключение: при отсутствии потокового буфера (когда rdbuf()==0) флаг badbit устанавливается всегда.
Следующий пример показывает, как установить и сбросить флаг failbit:
// Проверка установки флага failbit if (strm.rdstate() & std::ios::failbit) { std::cout << "failbit was set" << std::endl; // Сброс только флага failbit strm.clear (strm.rdstate() & ~std::ios::failbit); }
В этом примере используются поразрядные операторы & и ~. Оператор ~ возвращает поразрядное дополнение своего аргумента. Следовательно, показанное ниже выражение возвращает временное значение, в котором установлены все биты, кроме failbit:
~ios::failbit
Оператор & возвращает результат поразрядного объединения своих операндов. В результате операции устанавливаются только биты, установленные в обоих операндах. При поразрядном объединении всех текущих установленных флагов (rdstate()) cо всеми установленными битами, кроме failbit, бит failbit сбрасывается, а значения всех остальных битов сохраняются.
Потоки данных можно настроить так, чтобы при установке флагов функциями clear() и setstate() генерировались исключения.
Также следует помнить о необходимости явного сброса битов ошибок. Язык С позволял продолжить чтение символов после ошибки форматирования. Например, если функции scanf() не удавалось прочитать целое число, программа могла ввести оставшиеся символы. Таким образом, операция чтения завершалась неудачей, но входной поток данных оставался в нормальном состоянии. В C++ дело обстоит иначе. При установке бита failbit все последующие операции с потоком данных игнорируются до тех пор, пока флаг failbit не будет сброшен программой.
Вообще говоря, установленные флаги всего лишь отражают события, которые происходили в прошлом. Наличие установленного флага после какой-либо операции не всегда означает, что именно эта операция привела к его установке. Флаг также мог быть установлен еще до выполнения этой операции. Следовательно, если вы собираетесь проверять результат выполнения операции по состоянию флагов, перед ее выполнением следует привести поток данных к состоянию goodbit (если нет полной уверенности в том, что он уже находится в этом состоянии). Кроме того, после сброса флагов операция может вернуть другой результат. Например, даже если флаг eofbit в результате операции был установлен, это еще не означает, что после сброса eofbit (и всех остальных установленных битов) флаг будет снова установлен при повторном выполнении операции, поскольку между вызовами файл может увеличиться.
На следующем шаге мы рассмотрим состояние потока данных и логические условия.