Ввод-вывод с использованием потоковых классов. Потоковые классы char*

   
На этом шаге мы рассмотрим особенности использования потоковых классов char*.

   
Потоковые классы char* поддерживаются только в целях обратной совместимости. Их интерфейс иногда порождает ошибки, с этими
классами часто работают неправильно. Тем не менее они продолжают широко использоваться, поэтому далее приводятся их краткие описания.
Учтите, что в описываемой здесь стандартной версии прежний интерфейс был слегка изменен.

   
Далее вместо термина строка будет использоваться термин последовательность символов. Дело в том, что
последовательность символов, поддерживаемая потоковыми классами char*, не всегда заканчивается символом завершения строки (а
следовательно, не является строкой в обычном понимании).

   
Потоковые классы char* определены только для символьного типа char. К этой категории относятся следующие классы:

  • istrstream для чтения из последовательностей символов;
  • ostrstream для записи в последовательности символов;
  • strstream для чтения из последовательностей символов и записи в последовательности символов;
  • strstreambuf используется как потоковый буфер для потоков char*.

   
Потоковые классы char* определяются в заголовочном файле <strstream>.

   
Поток данных istrstream может инициализироваться последовательностью символов (типа char*), либо завершенной символом \0,
либо имеющей длину, переданную в аргументе. Типичный пример чтения и обработки строк:

char buffer[1000];        // Буфер, в которой могут храниться до 999 символов 
// Чтение строки 
std::cin.get(buffer,sizeof(buffer));
// Чтение/обработка строки как потока 
std::istrstream input(buffer);
.   .   .   .   .
input >> x;

   
Поток данных char*, предназначенный для записи, поддерживает последовательность символов, растущую по мере необходимости, или
инициализируется буфером фиксированного размера. При помощи флагов ios::app и ios::ate можно дописывать выводимые символы
к последовательности, уже хранящейся в буфере.

   
При строковой интерпретации потока данных char* необходима осторожность. В отличие от строковых потоков данных потоки типа char*
не всегда следят за использованием памяти, в которой хранится последовательность символов.

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

  • Поскольку права владения памятью передаются вызывающей стороне (если поток данных не был инициализирован буфером фиксированного
    размера), символьная последовательность должна освобождаться. Но так как не гарантируется, что память выделялась, вызов delete[] не
    всегда безопасен. Лучше всего вернуть память в поток данных вызовом функции freeze с аргументом false (пример приводится далее).
  • Вызов str() запрещает потоку данных дальнейшее изменение последовательности символов. Функция неявно вызывает функцию freeze(),
    которая фиксирует ("замораживает") последовательность символов. Это делается для того, чтобы избежать трудностей при недостаточном размере
    буфера и необходимости выделять новую память.
  • Функция str() не присоединяет символ завершения строки ('\0'). Это символ приходится отдельно присоединять к потоку
    данных для завершения последовательности символов. Задача решается при помощи манипулятора ends. Некоторые реализации присоединяют
    символ завершения строки автоматически, но это поведение нарушает переносимость программы.

   
Пример использования потока char*:

float x;
// Создание и заполнение потока char*
// - не забывайте о ends или '\0'!!!
std::ostrstream buffer;      // Динамический потоковый буфер 
buffer << "float х: " << х << std::ends;
// Передача полученной С-строки функции foo() и возвращение памяти в буфер
char* s = buffer.str();
foo(s);
buffer.freeze(false);

   
Зафиксированный поток char* можно привести в обычное состояние для дополнительной обработки. Для этого следует вызвать функцию
freeze() с аргументом false. При выполнении этой операции право владения последовательностью символов снова возвращается
объекту потока данных. Это единственный безопасный способ освобождения памяти для последовательности символов. В следующем примере
показано, как это делается:

float х;
std::ostrstream buffer;   // Динамический поток char*
// Заполнение потока char*
buffer << "float x: " << x << std::ends;
// Передача итоговой С-строки функции foo()
//   - фиксация потока char*
foo(buffer.str());
// Снятие фиксации с потока char* 
buffer.freeze(false);
// Установка позиции записи в начало 
buffer.seekp (0,ios::beg);
// Повторное заполнение потока char*
buffer << "once more float x: " << x << std::ends;
// Повторная передача полученной С-строки функции foo()
//  - фиксация потока char*;
foo(buffer.str());
// Возвращение памяти в буфер 
buffer.freeze(false);

   
Проблем, возникающих из-за фиксации потока данных, нет в классах строковых потоков данных. В основном это объясняется тем, что использование
памяти при копировании находится под контролем строкового класса.

   
Со следующего шага мы начнем рассматривать операторы ввода-вывода для пользовательских типов.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий