Состояния потока. Ошибки потоков

Состоянием потока можно управлять с помощью перечисленных ниже методов и операций:

int rdstate()-возвращает текущее состояние потока

int eof()-возвращает ненулевое значение, если установлен флаг eofbit

int fail()-возвращает ненулевое значение, если установлен один из флагов failbit,badbit или hardbit

int bad()-возвращает ненулевое значение, если установлен один из флагов badbit или hardbit

int good()-возвращает ненулевое значение, если сброшены все флаги ошибок

void clear(int i=0)-параметр принимает в качестве состояния ошибки, при отсутствии параметра состояние ошибки устанавливается 0;

operator void*()-возвращает нулевой указатель, если установлен хотя бы один бит ошибки

operator !()- возвращает ненулевой указатель, если установлен хотя бы один бит ошибки

далее приведены часто используемые операции с флагами состояния потока

//проверить, установлен ли флаг flag

if(stream_obj.rdstate() & ios::flag)

//сбросить флаг flag

stream_obj.clear(rdstate() &~ ios::flag)

// установить флаг flag

stream_obj.clear(rdstate() │ ios::flag)

// установить флаг flag и сбросить все остальное

stream_obj.clear(ios::flag)

//сбросить все флаги

stream_obj.clear()

операция void*() неявно вызывается всякий раз, когда поток сравнивается с 0. Это позволяет записать циклы вида:

while(stream_obj){

//все в порядке можно поизводить ввод/вывод}

Ошибки потоков

В баз классе ios определено поле state которое представляет собой состояние потока в виде совокупности битов:

enum io_state{

goodbit =0x00.//нет ошибок

eofbit=0x01.//достигнут конец файла

failbit=0x02.//ошибка форматирования или преобразования

badbit=0x04.//серьезная ошибка, после которой пользоваться потоком невозможно

hardfail=0x08.//неисправность оборудования

};

 


43. Форматирование в си++. Форматирующие функции-члены. Форматирующие функции – элементы, изменяющие флаги форматирования. Управление потоков с помощью манипулятора.

Для управления форматированием ввода-вывода предусмотрены три вида средств: форматирующие функции, флаги и манипуляторы. Все эти средства являются членами класса ios и потому доступны для всех потоков.

Форматирование

Непосредственное применение операций ввода << и вывода >> к стандартным потокам cout, cin, cerr, clog для данных базовых типов приводит к использованию ''умалчиваемых'' форматов внешнего представления пересылаемых значений.

Форматы представления выводимой информации и правила восприятия данных при вводе могут быть изменены программистом с помощью флагов форматирования. Эти флаги унаследованы всеми потоками из базового класса ios. Флаги форматирования реализованы в виде отдельных фиксированных битов и хранятся в protected компоненте класса long x_flags. Для доступа к ним имеются соответствующие public функции.

Кроме флагов форматирования используются следующие protected компонентные данные класса ios :

int x_width - минимальная ширина поля вывода.

int x_precision - точность представления вещественных чисел (количество цифр дробной части) при выводе;

int x_fill - символ-заполнитель при выводе, пробел - по умолчанию.

Для получения (установки) значений этих полей используются следующие компонентные функции:

int width(void);int width(int);int precision(void);int precision(int);char fill(void);char fill(char);

форматирующие функции-члены. Их всего три: width(), precision() и fill().

По умолчанию при выводе любого значения оно занимает столько позиций, сколько символов выводится. Функция width() позволяет задать минимальную ширину поля для вывода значения. При вводе она задает максимальное число читаемых символов. Если выводимое значение имеет меньше символов, чем заданная ширина поля, то оно дополняется символами-заполнителями до заданной ширины (по умолчанию - пробелами). Если же выводимое значение имеет больше символов, чем ширина отведенного ему поля, то поле будет расширено до нужного размера. Эта функция имеет следующие прототипы:

int width(int wide);
int width() const;

Функция с первым прототипом задает ширину поля wide, а возвращает предыдущее значение ширины поля. Функция со вторым прототипом возвращает текущее значение ширины поля. По умолчанию она равна нулю, то есть вывод не дополняется и не обрезается. В ряде компиляторов после выполнения каждой операции вывода значение ширины поля возвращается к значению, заданному по умолчанию.

Функция precision() позволяет узнать или задать точность (число выводимых цифр после десятичной точки), с которой выводятся числа с плавающей точкой. По умолчанию числа с плавающей точкой выводятся с точностью, равной шести цифрам. Функция precision () имеет следующие прототипы:

int precision(int prec);
int precision() const;

Функция с первым прототипом устанавливает точность в prec и возвращает предыдущую точность. Функция со вторым прототипом возвращает текущую точность.

Функция fill() позволяет прочесть или установить символ-заполнитель. Она имеет следующие прототипы:

char fill(char type ch);
char fill() const;

Функция с первым прототипом устанавливает ch в качестве текущего символа-заполнителя и возвращает предыдущий символ-заполнитель. Функция со вторым прототипом возвращает текущий символ-заполнитель. По умолчанию в качестве символа-заполнителя используется пробел.

С каждым потоком связан набор флагов, которые управляют форматированием потока. Они представляют собой битовые маски, которые определены в классе ios как данные перечисления.

Манипуляторы

Несмотря на гибкость и большие возможности управления форматами с помощью компонентных функций класса ios , их применение достаточно громоздко. Более простой способ изменения параметров и флагов форматирования обеспечивают манипуляторы.

Манипуляторами называются специальные функции, позволяющие модифицировать работу потока. Особенность манипуляторов состоит в том, что их можно использовать в качестве правого операнда операции >> или << . В качестве левого операнда, как обычно, используется поток (ссылка на поток), и именно на этот поток воздействует манипулятор. Манипуляторы указывают, например, ширину поля, точность при вычислении с плавающей точкой и т.п.

Для обеспечения работы с манипуляторами в классах istream и ostream имеются следующие перегруженные функции operator.

istream &operator >>(istream &(*_f)(istream &));ostream &operator <<(ostream &(*_f)(ostream &));

При использовании манипуляторов следует включить заголовочный файл <iomanip.h>, в котором определены встроенные манипуляторы. Манипуляторы действуют на ввод-вывод в поток до внесения новых изменений.

Флаги форматирования

 

dec Устанавливает 10-тичную систему счисления. Воздействует на int и long.
  Потоки используют основание 10 по умолчанию.
hex Устанавливает 16-ричную систему счисления.
oct Устанавливает 8-ричную систему счисления.
ws Выбирает из потока ввода символы пропуска. Поток будет читаться
  до появления символа, отличного от пропуска, или до возникновения
  ошибки потока.
endl Вставляет в поток вывода символ новой строки и затем сбрасывает поток.
ends Вставляет '\0' в поток вывода.
flush Сбрасывает поток вывода.

setbase() устанавливает основание счисления к любому из четырех значений:

Основание по умолчанию. При выводе 10-тичное, при вводе - числа,
  начинающиеся с '0', считаются 8-ричными, начинающиеся с '0x',
  - 16-ричными. Во всех остальных случаях основание считается 10-тичным.
Для ввода-вывода используется основание 8.
Для ввода-вывода используется основание 10.
Для ввода-вывода используется основание 16.

44. Шаблоны функций С++

Шаблон функциипредставляет собой обобщенное определение из которого компилятор может автоматически генерировать код (создать представителя функции).

template<список аргументов шаблона>

тип имя_функции(параметры...)

{

//тело функции

}

Каждый элемент шаблона представляет собой:

class идентификатор

template<class T>

void Swap(T t[], int i1, int i2)

{

T tmp=t[i1];

t[i1]=t[i2];

t[i2]=tmp;

}

//шаблон функции с 2 параметрами одного и того же

template<class T>

void f1(T t1, T t2) {...}

//шаблон функции с 2 параметрами разного типа

template<class T1, class T2>

void f2(T1 t1, T2 t2) {...}

Шаблон функции для сортировки произвольного массива:

template<class T>

void Sort(T arr1, int size)

{

for(int i=0,i<size-1;i++)

{

for(j=0,i<j;j--)

{

if(arr[j-1]>arr[i])

{

T tmp=arr[j];

arr[j]=arr[j-1];

arr[j-1]=tmp;

}

}

}

}

Для типов пользователя надо переопределить операцию отношения «больше >».

Т. к. код в шаблонах используется только при вызове, то шаблон принято писать в заголовочном файле. Шаблоны плохие кандидаты для раздельной компиляции. Можно создать прототип функции, который будет информировать компилятор о наличии шаблона и о его ожидаемых параметрах.

template<class T>

void Sort(T arr1, int size);

После определения шаблона, его можно сразу же использовать.

#include <iostream.h>

#include “sort_template”

int main()

{

int A={1,2,5,4,3,8};

int size=sizeof();

} Этот же шаблон можно использовать и для сортировки элементов, типы которых определяются пользователем.

class Time

{

int hour, minutes;

public:

Time(int h, int m){hour=h;minutes=m};

int operator>(const Time &t) const

{

return((hour>t.hour)||hour==t.hour && minutes==t.minutes)

}

}

int main()

{

TimeArray[]={Time(12,15), Time(11,30), Time(02,50)};

int size=(sizeof(TimeArray[])/sizeof(TimeArray[0]));

...}

Точно так же как и обычные функции, функциональные шаблоны могут быть перегружены. Т.е. можно предусмотреть несколько шаблонов функции с одним и тем же именем. Если только они имеют различные сигнатуры.