Любой поток в каждый момент времени находится в определенном состоянии. Учитывая это состояние, осуществляется обработка ошибок и нестандартных условий. Поток может находиться в одном из состояний, определенных перечислением io_state в классе ios. Например:
class _CRTIMP ios
{
…
public:
enum io_state
{
goodbit = 0x00, // нет установленных битов ошибки. Операция прошла
// успешно;
eofbit = 0x01, // конец файла. Нет больше символов для ввода;
failbit = 0x02, // последняя операция закончилась с ошибкой;
badbit = 0x04 // попытка ввода-вывода закончилась ошибкой;
};
};
Таким образом, переменная перечисления типа io_state устанавливается в то или иное состояние в зависимости от того, как прошла последняя операция. Если состояние потока goodbit или eofbit, значит, последняя операция ввода-вывода прошла успешно. Состояние потока goodbit означает, что можно выполнять следующую операцию, и она может пройти успешно.
В случае, когда поток находится в любом другом состоянии, попытка чтения закончится неудачей. В состоянии badbit в принципе поток может быть разрушен. Как только поток установится в состояние ошибки (failbit, badbit), все попытки чтения будут игнорироваться до тех пор, пока не будет очищен соответствующий бит в переменной состояния потока. Очистить переменную потока можно, например, член-функцией ios::clear(J), которая фактически просто устанавливает переменную состояния в целое, заданное аргументом J. Так, например, ios::clear(0) очищает все биты ошибок.
Практически всегда нужно проверять состояние потока после операции ввода-вывода. Это относится к хорошему стилю программирования, потому что плохо выполненный ввод-вывод может послужить впоследствии источником многих ошибок.
Состояние потока можно проверить, например, используя член-функцию rdstate(). Эта функция возвращает состояние ошибки в виде величины int. Затем эту величину можно проверить на то, какая ситуация имела место. Например:
switch (сin.rdstate())
{
case ios::goodbit :
cout << "Последняя операция над cin прошла успешно n";
break;
case ios::eofbit :
cout << "Конец файла n";
break;
case ios::failbit :
cout << "Имела место ошибка ввода-выводаn";
break;
case ios::badbit :
cout << "Произошла ошибка, возможна потеря символов cin n";
break;
};
Альтернативный метод проверки состояния потока – это использование функций eof(), fail(), bad(), good(). Это член-функции класса ios, проверяющие соответствующие биты и возвращающие истину (не нуль), если бит установлен, и ложь (нуль), если бит не установлен. Например:
class ios {
public:
inline int rdstate() const; // Возвращает текущее состояние ошибки
inline void clear(int _i = 0); // Устанавливает переменную состояния _i
inline int good() const; // Возвращает не нуль, если нет установленных
// битов ошибки; в противном случае возвращает нуль
inline int eof() const; // Возвращает не нуль, если установлен eofbit;
// в противном случае возвращает нуль
inline int fail() const; // Возвращает не нуль, если установлен failbit,
// в противном случае возвращает нуль
inline int bad() const; // Возвращает не нуль, если установлен badbit;
// в противном случае возвращает нуль
…
};
Состояние потока может быть проверено и как обычное логическое выражение. Например:
if (cin >> ch) cout << "Символ введен n";
или
if (!cin) cerr << "Ошибка ввода n";
Выражение cin >> ch представляет обычное логическое выражение, значение которого может быть либо не нуль – истина, либо нуль – ложь. Это возможно, так как класс ios определяет две перегружаемые операции:
int operator !(); и operator void * ();
Функция operator void * () определяет операцию преобразования из типа потока в тип указателя на void. Эта операция преобразования возвращает нуль (ложь), если установлены биты failbit и badbit, в противном случае возвращается не нуль (истина). Заметим, что во многих реализациях состояние конца файла (eofbit) не трактуется как ошибка, и поэтому не может быть проверено таким способом. Для отслеживания состояния конца файла нужно применить либо функцию rdstate(), либо функцию eof(). Это будет гарантировать переносимость программы. Перегруженная операция отрицания (!) возвращает не нуль (истину), если поток установлен в одно из состояний failbit, badbit, в противном случае возвращается нуль (ложь).
Необходимо отметить, что операция преобразования потокового объекта в тип указателя на void используется только при логической проверке и не имеет никаких других практических применений. Подобный метод проверки тестирует поток на состояние ошибки. Чтобы конкретизировать состояние, нужно использовать одну из рассмотренных член-функций.