Hi ALL.Столкнулся с классом ostrstream, позволяющим писать в буфер.
В цикле у меня вызывется функция, в которой формируется буфер, с помощью данного класса. Причем буфер бывает разной длины, в зависимости от данных. У меня появляются концы старых, более длинных, строк. Хотя при выходе из функции объект класса должен уничтожаться, зн. и внутренний буфер со старыми данными, тоже должен исчезнуть.
Я вывожу сформированные данные на stdout, получив до этого замороженный буфер посредством метода str() (потом я удаляю этот буфер оператором delete[]). Свои изыскания я основывал на книге Тереса Чана "Системное программирование на С++ для Unix".
Если предположить, что внутри класса используется статический буфер, не уничтожающийся при выходе из функции, то все равно он должен выставлять корректный размер данных при входе в эту функцию снова.Может кто сталкивался с подобным явлением. У меня стоит Fedore Core 1, gcc 3.3.3.
Благодарю за внимание.
Ты имееш ввиду класс ostringstream? Покажи код...
>Ты имееш ввиду класс ostringstream? Покажи код...Пример:
// cut here ------------
#include <strstream>
#include <iostream>
#include <string>
using namespace std;string str[4] = {"str1", "str1str2", "str1str2str3", "sr"};
int i = 0;char *Func()
{
ostrstream s_out;
s_out << "String " << str[i] << endl;
return s_out.str();
}int main()
{
for(; i < 4; i++)
{
char *s = Func();
cerr << s;
delete[] s;
}
cerr << endl;
return 0;
}// cut here ------------
при работе выдает следующий результат:
String str1
String str1str2
String str1str2str3
String sr
1str2sпоследней строки быть не должно !!!
#include <sstream>
#include <iostream>
#include <string>
std::string str[4] = {"str1", "str1str2", "str1str2str3", "sr"};
int i = 0;
char* Func()
{
std::ostringstream s_out;
s_out << "String " << str[i] << std::endl;
return (s_out.str()).c_str(); // !!!!!
}int main()
{
for(; i < 4; i++) {char *s = Func();
std::cout << s;
//delete [] s;
}std::cout << std::endl;
return 0;
}
>char* Func()
>{
> std::ostringstream s_out;
> s_out << "String " << str[i] << std::endl;
> return (s_out.str()).c_str(); // !!!!!
>}Вот это то же не должно работать. s_out размещается в стеке и уничтожается при выходе из функции, а вместе с ней и строка которая была записана.
Надо либо вообще все переделать либо сделать что-то вроде
#include <sstream>
#include <iostream>
#include <string>
std::string str[4] = {"str1", "str1str2", "str1str2str3", "sr"};
int i = 0;
std::string Func()
{
std::ostringstream s_out;
s_out << "String " << str[i] << std::endl;
return s_out.str();
}int main()
{
for(; i < 4; i++) {std::string s(Func());
std::cout << s;
//delete [] s;
}std::cout << std::endl;
return 0;
}
>Вот это то же не должно работать. s_out размещается в стеке
>и уничтожается при выходе из функции, а вместе с ней и
>строка которая была записана.
Память под char* выделяется статически !!!, поэтому после вызова функции не освобождается
>Память под char* выделяется статически !!!, поэтому после вызова функции не освобождаетсяНе понял что ты этим хотел сказать.
Посмотри исходный текст std::strsream:
typedef basic_string<char_type, _Traits, _Alloc> __string_type;
// Get and set:
/**
* @brief Copying out the string buffer.
* @return A copy of one of the underlying sequences.
*
* "If the buffer is only created in input mode, the underlying
* character sequence is equal to the input sequence; otherwise, it
* is equal to the output sequence." [27.7.1.2]/1
*/
__string_type
str() const
{
if (_M_mode & ios_base::out)
{
// This is the deal: _M_string.size() is a value that
// represents the size of the initial string that makes
// _M_string, and may not be the correct size of the
// current stringbuf internal buffer.
__size_type __len = _M_string.size();
if (_M_out_end > _M_out_beg)
__len = max(__size_type(_M_out_end - _M_out_beg), __len);
return __string_type(_M_out_beg, _M_out_beg + __len);
}
else
return _M_string;
}Другими словами создается новый экземпляр __string_type. В случае std::ostrstream тип __string_type эквивалентен std::string. Метод c_str() у std::string не выделяет память а возвращает указатель на свой внутренний буфер (поэтому его не надо освобождать).
Другими словами, код
const char *foo() {
std::string s("la-la-la");
return s.c_str();
}будет возвращать неправильный указатель потому что строка s будет уничтожена при возврате из функции. Код
return (s_out.str()).c_str();
не будет работать правильно по той же причине. Более того, специально для таких случаев метод c_str() возвращает не просто char*, а const char*, поэтому этот код даже не откомпилируется.
На практике можно явно преобразовать const char* в char* и это, возможно, даже будет иногда работать в зависимости от состояния кучи и стека. Но состояние кучи и стека не всегда будет оставаться благоприятным поэтому ошибка рано или поздно даст о себе знать.
>Вот это то же не должно работать. s_out размещается в стеке и >уничтожается при выходе из функции, а вместе с ней и строка которая была >записана.Почти все правильно кроме одного что мы получаем при помощи c_str() следующий тип char* и этот тип всегда будет static поэтому и остается в стеке. Но ты прав с константой. Да c_str() возращает тип const char* поэтому пишим
const_cast<char*>((s_out.str()).c_str())
Но это уже извращение да и функция char* Func() не нужна.
>Почти все правильно кроме одного что мы получаем при помощи c_str() следующий
>тип char* и этот тип всегда будет static поэтому и остается
>в стеке.Да, на счет этого я был не прав. Действительно получается static, поэтому никаких проблем с памятью не будет.
>>Вот это то же не должно работать. s_out размещается в стеке и >уничтожается при выходе из функции, а вместе с ней и строка которая была >записана.
>
>Почти все правильно кроме одного что мы получаем при помощи c_str() следующий
>тип char* и этот тип всегда будет static поэтому и остается
>в стеке. Но ты прав с константой. Да c_str() возращает тип
>const char* поэтому пишим
>const_cast<char*>((s_out.str()).c_str())
>Но это уже извращение да и функция char* Func() не нужна.Доброго времени суток,
Простите, но откуда здесь static?
Ваше мнение к сожалению ложно. Как сказал предидущий оратор - это работать если и будет, то только случайно при определенных условиях.
Стандарт четко говорит, что возвращаемый c_str const указатель верен ТОЛЬКО пока строка (объект класса) существует и пока не была вызвана хотя бы одна не константная функция.
Удачи
--- sas
>Доброго времени суток,
>
>Простите, но откуда здесь static?Стандарт четко говорит что char* всегда будет static char*
>
>Ваше мнение к сожалению ложно. Как сказал предидущий оратор - это работать
>если и будет, то только случайно при определенных условиях.
>
>Стандарт четко говорит, что возвращаемый c_str const указатель верен ТОЛЬКО пока
>строка (объект класса) существует и пока не была вызвана хотя бы
>одна не константная функция.
>
>Удачи
>--- sas
>>Доброго времени суток,
>>
>>Простите, но откуда здесь static?
>
>Стандарт четко говорит что char* всегда будет static char*
>
>>
>>Ваше мнение к сожалению ложно. Как сказал предидущий оратор - это работать
>>если и будет, то только случайно при определенных условиях.
>>
>>Стандарт четко говорит, что возвращаемый c_str const указатель верен ТОЛЬКО пока
>>строка (объект класса) существует и пока не была вызвана хотя бы
>>одна не константная функция.
>>
>>Удачи
>>--- sasЯ прошу прощения и где он это говорит? Ссылочка или хотя-бы пункт помогли бы отцу русской демократии :)
Удачи
--- sas
Строковым литералом называется последовательность символов заключенная в двойные кавычки:
“Это строка”
.....Память под строкавые литералы выделяется статически поэтому их свободно можно возращать в качестве значения функции. Например:
const char* error_message(int i)
{
// ...
retrun “Выход за пределы диапазона”;
}
Память содержащая строку “Выход за пределы диапазона” не будет освобождена после вызова error_message().Стр. 130 Глава 5.2.2. “Язык программирования С++ специальное издание” Bjarne Stroustrup
>Строковым литералом называется последовательность символов заключенная в двойные кавычки:
>?Это строка?
>.....
>
>Память под строкавые литералы выделяется статически поэтому их свободно можно возращать в
>качестве значения функции. Например:
> const char* error_message(int i)
> {
> // ...
> retrun ?Выход за пределы диапазона?;
> }
>Память содержащая строку ?Выход за пределы диапазона? не будет освобождена после вызова
>error_message().
>
>Стр. 130 Глава 5.2.2. ?Язык программирования С++ специальное издание? Bjarne Stroustrup
>Прекрасно!!! :)) Возразить НЕЧЕГО... И где же здесь аналогия с нашим случаем?
Удачи
--- sas
>Строковым литералом называется последовательность символов заключенная в двойные кавычки:
>?Это строка?
>.....
>Ну и что ? Да "String " и "str1str2str3" - static const char*, но неужели ты думаеш что (std::string("String ") + "str1str2str3") все еще static !?
>Строковым литералом называется последовательность символов заключенная в двойные кавычки:
>?Это строка?
>.....
>
>Память под строкавые литералы выделяется статически поэтому их свободно можно возращать в
>качестве значения функции. Например:
> const char* error_message(int i)
> {
> // ...
> retrun ?Выход за пределы диапазона?;
> }
>Память содержащая строку ?Выход за пределы диапазона? не будет освобождена после вызова
>error_message().
>
>Стр. 130 Глава 5.2.2. ?Язык программирования С++ специальное издание? Bjarne Stroustrup
>Уважаемый solov!
А вдогонку вопрос: А можно менять постоянные статические строки?
Удачи
--- sas
>Строковым литералом называется последовательность символов заключенная в двойные кавычки:
>?Это строка?
>.....
>
>Память под строкавые литералы выделяется статически поэтому их свободно можно возращать в
>качестве значения функции. Например:
> const char* error_message(int i)
> {
> // ...
> retrun ?Выход за пределы диапазона?;
> }
>Память содержащая строку ?Выход за пределы диапазона? не будет освобождена после вызова
>error_message().
>
>Стр. 130 Глава 5.2.2. ?Язык программирования С++ специальное издание? Bjarne Stroustrup
>Уважаемый Mr Solov,
И еще один вопрос: Меняется ли содержимое объекта (i|o)stringstream в процессе его жизнидеятельности?
Удачи
--- sas
Всем спасибо, разобрался.
Плохо, когда нет хорошего хелпа с возможностью поиска.
>Hi ALL.
>
>Столкнулся с классом ostrstream, позволяющим писать в буфер.
>В цикле у меня вызывется функция, в которой формируется буфер, с помощью
>данного класса. Причем буфер бывает разной длины, в зависимости от данных.
>У меня появляются концы старых, более длинных, строк. Хотя при выходе
>из функции объект класса должен уничтожаться, зн. и внутренний буфер со
>старыми данными, тоже должен исчезнуть.
>Я вывожу сформированные данные на stdout, получив до этого замороженный буфер посредством
>метода str() (потом я удаляю этот буфер оператором delete[]). Свои изыскания
>я основывал на книге Тереса Чана "Системное программирование на С++ для
>Unix".
>Если предположить, что внутри класса используется статический буфер, не уничтожающийся при выходе
>из функции, то все равно он должен выставлять корректный размер данных
>при входе в эту функцию снова.
>
>Может кто сталкивался с подобным явлением. У меня стоит Fedore Core 1,
>gcc 3.3.3.
>
>Благодарю за внимание.Для полноты картины, хотя и несколько поздновато:
Объекты классов (i|o|)strstream являются устаревшими. По стандарту пользователь обязан сам "закрывать" строку добавляя ends, если ему это нужно.
...
ostrstream s_out;
s_out << "String " << str[i] << "\n" << ends;
return s_out.str();
...Массив который Вы возвращаете выделен из динамической памяти
Как уже было указано лучше использовать stringstream.
Удачи
--- sas
Гораздо более полное и понятное объяснение чем мое :)http://docs.freebsd.org/info/iostream/iostream.info.Strings....
Удачи
--- sas>>Hi ALL.
>>
>>Столкнулся с классом ostrstream, позволяющим писать в буфер.
>>В цикле у меня вызывется функция, в которой формируется буфер, с помощью
>>данного класса. Причем буфер бывает разной длины, в зависимости от данных.
>>У меня появляются концы старых, более длинных, строк. Хотя при выходе
>>из функции объект класса должен уничтожаться, зн. и внутренний буфер со
>>старыми данными, тоже должен исчезнуть.
>>Я вывожу сформированные данные на stdout, получив до этого замороженный буфер посредством
>>метода str() (потом я удаляю этот буфер оператором delete[]). Свои изыскания
>>я основывал на книге Тереса Чана "Системное программирование на С++ для
>>Unix".
>>Если предположить, что внутри класса используется статический буфер, не уничтожающийся при выходе
>>из функции, то все равно он должен выставлять корректный размер данных
>>при входе в эту функцию снова.
>>
>>Может кто сталкивался с подобным явлением. У меня стоит Fedore Core 1,
>>gcc 3.3.3.
>>
>>Благодарю за внимание.
>
>Для полноты картины, хотя и несколько поздновато:
>
>Объекты классов (i|o|)strstream являются устаревшими. По стандарту пользователь обязан сам "закрывать" строку
> добавляя ends, если ему это нужно.
>...
> ostrstream s_out;
> s_out << "String " << str[i] << "\n" << ends;
> return s_out.str();
>...
>
>Массив который Вы возвращаете выделен из динамической памяти
>
>Как уже было указано лучше использовать stringstream.
>
>Удачи
>--- sas