LINUX.ORG.RU

проблема с функцией (утечка памяти), С++ ((


0

0

есть такая функция:

template<class X>
const string convert_val_to_string(const X val)
{
std::ostrstream str;
char* pstr = 0;
str << val << '\0';
pstr = str.str();
const string ret_string = pstr;
return ret_string;
}

если пустить в бесконечный цикл, то вскоре засерает под себя всю память, где ошибка?

Ответ на: комментарий от hello_world

ну вот смотри:

объявил
std::ostrstream str;

записал, как думаешь куда оно записалось? Если в стек,
str << val << '\0';

то этот указатель внезапно может оказаться недействителен
pstr = str.str();

, а если не в стек то значит была выделена память => смотри исходники, возможно память выделяется в str.str().

вот собстно исходник http://www.opennet.ru/openforum/vsluhforumID9/2647.html#7

wfrr ★★☆
()

> если пустить в бесконечный цикл, то вскоре засерает под себя всю память, где ошибка?

pstr = str.str();
const string ret_string = pstr;
delete[] pstr; // <-- вот
return ret_string;

Eshkin_kot ★★
()
Ответ на: комментарий от Eshkin_kot

> delete[] pstr; // <-- вот

тогда вообще всё сдохнет.

Тут была сразу несовсем обдуманная идея возвращать const string - смысла в этой мнимой экономии нету; равно как и указатель там лишний; когда временный ostrstream будет умирать в стеке, то его буфер унаследуется вновь созданному string, который в свою очередь тоже умрет, но указатель перейдет возвращаемому объекту. Экономить на создании поинтера и счетчиков при создании нового string - это явная переоптимизация которая яйца выеденного не стоит.

template<class X> string convert_val_to_string(const X val) {

std::ostrstream str;

str << val;

return string(str.str());

}

если уж пользуешся STL, то не думай как на C.

anonymous
()
Ответ на: комментарий от wfrr

> А конструктор стринга случайно не скопирует строку?

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

string a = "string 1";

string b = a;

char *ptr = const_cast<char *>(a.c_str());

ptr[7] = '2';

cout << a << endl;

cout << b << endl;

оба вывода будут "string 2", если конечно не пользоватся кривыми реализациями вроде как в старых VC.

anonymous
()
Ответ на: комментарий от anonymous

согласен, да и компилятор намекал об этом )))

In file included from /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/backward/str stream:51, from ./source/main.cpp:24: /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/backward/bac kward_warning.h:32:2: error: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <iostream> instead of the deprecated header <iostream.h>. To disable this warning use -Wno-deprecated.

hello_world
() автор топика
Ответ на: комментарий от hello_world

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

hello_world
() автор топика
Ответ на: комментарий от hello_world

да и что думаете об этом?
const string get_time()
{
time_t time_v = time(0);
return ctime(&time_v);
}

const string cget_integer_time()
{
return convert_val_to_string(time(0));
}

hello_world
() автор топика
Ответ на: комментарий от hello_world

1. какой смысл возвращать const string ?

2. ostrstream deprecated и надо использовать ostringstream

3. твой велосипед давно уже изобретен в boost::lexical_cast

Reset ★★★★★
()
Ответ на: комментарий от Reset

> 3. твой велосипед давно уже изобретен в boost::lexical_cast

IMO, этот пункт тут явно лишний; это личное дело каждого, какие велосипеды изобратать, и какие либы использовать. В конце концов, зачем тогда было Linux писать, да и кучу прог, у которых уже были аналоги - или сейчас, когда делаются аналоги уже существующих OpenSource прог.

В конце концов, есть такое банальное понятие - как учеба, когда ты только и делаешь что переизобретаешь велосипеды.

anonymous
()
Ответ на: комментарий от Reset

>3. твой велосипед давно уже изобретен в boost::lexical_cast
Зачем учить таблицу умножения? Ведь всё уже подсчитано до вас!

hello_world
() автор топика
Ответ на: комментарий от hello_world

>Да и потом наверняка побыстрее будет...

ээ. придумай хоть одну причину (даже не прошу назвать), почему const быстрее?

xydo ★★
()
Ответ на: комментарий от hello_world

Побыстрее не будет. А константность тут не несет никакого логического смысла. Если бы у тебя это указатель был или ссылка тогда можно было еще понять.

Reset ★★★★★
()
Ответ на: комментарий от hello_world

Сам то понял что сказал? Как можно что-то кинуть в память из которой можно только читать? Тогда это получается уже не "память, откуда можно только читать".

Reset ★★★★★
()
Ответ на: комментарий от hello_world

>> 1. какой смысл возвращать const string > А что в этом плохого?

на самом деле это плохо. Ты ограничиваешь пользователя функции без какой-либо на то причины. Объект ты вновь создаешь - смысл возвращать const только если ты возвращаешь ссылку на объект который уже существовал, и не хочешь чтобы клиент его менял.

В твоем же случае, возвращаемый объект вновь созданный и никому кроме клиента не нужен. А вот объект который ты вернешь клиент менять не сможет - ему придется создавать копию объекта, который интересовал только его и никому больше не нужен.

> Да и потом наверняка побыстрее будет...

быстрее если возвращать ссылку, но ссылка на временный объект из стека не имеет смысла - не знаю, обругает ли тебя при этом компилятор.

anonymous
()
Ответ на: комментарий от anonymous

зашита от случайной модификации, все равно результат этой опирации будет кудато копироваться

hello_world
() автор топика
Ответ на: комментарий от hello_world

Это правильно. Если не const, то будет допустима бессмысленная конструкция func() = "abc";

Например, частое ошибочное использование = вместо сравнения в условии: if (func() = "abc").

Если будет const, то такой ошибки не возникнет. Вообще это у Страуструпа описано: функции должны возвращать r-value, чтобы избежать трудноотлавливаемых ошибок, что достигается использованием модификатора const.

sergio_nsk
()
Ответ на: комментарий от sergio_nsk

> Например, частое ошибочное использование = вместо сравнения в условии: if (func() = "abc")

Такой код все равно не скомпилируется - std::string не конвертируется в bool. И для таких случаев есть стандартный совет - в условиях писать константу слева от оператора, т.е. if ("abc" == func()). Это работает для любых типов и при любом определении функции.

Имхо: такие ошибки тривиальны и совершаются максимум 2-3 раза. Смысла "отлавливать" их специально нет.

> функции должны возвращать r-value, чтобы избежать трудноотлавливаемых ошибок, что достигается использованием модификатора const.

Ужос :) Хорошо что никто не следует такому "соглашению". Излишнее использование const только загромождает код. А в этом случае оно еще и неудобно - теперь придется создавать временную строку для выражений типа func().erase(0,4)

Мне непонятно желание многих программеров затолкать в код побольше граблей - "чтобы было сложнее ошибиться". А почему не сделать так, чтобы было проще писать правильно? Упростить код до предела, написать комментарии и примеры, и т.д.

А от дурака и опечатки при копипасте все равно никакие assert'ы не помогут.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.