13.2  Состояние потока

Любой поток в каждый момент времени находится в определен­ном состоянии. Учитывая это состояние, осуществляется обработка ошибок и нестандартных условий. Поток может находиться в одном из состояний, определенных перечислением 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. Затем эту величину можно проверить на то, какая ситуация имела место. Например:

switchin.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 >> chcout << "Символ введен n";

или

if (!cin) cerr << "Ошибка ввода n";

Выражение cin >> ch представляет обычное логическое выраже­ние, значение которого может быть либо не нуль – истина, либо нуль – ложь. Это возможно, так как класс ios определяет две пере­гружаемые операции:

int operator !();  и    operator void * ();

Функция operator void * () определяет операцию преобразова­ния из типа потока в тип указателя на void. Эта операция преобра­зования возвращает нуль (ложь), если установлены биты failbit и badbit, в противном случае возвращается не нуль (исти­на). Заметим, что во многих реализациях состояние конца файла (eofbit) не трактуется как ошибка, и поэтому не может быть прове­рено таким способом. Для отслеживания состояния конца файла нужно применить либо функцию rdstate(), либо функцию eof(). Это будет гарантировать переносимость программы. Перегружен­ная операция отрицания (!) возвращает не нуль (истину), если поток установлен в одно из состояний failbit, badbit, в противном случае возвращается нуль (ложь).

Необходимо отметить, что операция преобразования потоково­го объекта в тип указателя на void используется только при логиче­ской проверке и не имеет никаких других практических примене­ний. Подобный метод проверки тестирует поток на состояние ошибки. Чтобы конкретизировать состояние, нужно использовать одну из рассмотренных член-функций.