![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
ama_kid |
|
||||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 2 Всего: 95 |
Доброго всем времени суток...
Сразу скажу, что при написании топика почитал эту и эту тему, выданные мне форумом как "похожие темы", ответы там не сильно помогли, поиском тоже пользовался - не айс... между тем вопрос по большому счету не стОит и того количества букв, которые я тут напишу, но тем не менее, постараюсь в красках и примерах на пальцах объяснить суть ментального геморроя... Итак, недавно пришлось переводить кое-какой код с Дельфи на С++ и столкнулся с интересной для себя теоретической проблемой, которая подспудно грызла меня давно, но как-то не было случая с ней основательно разобраться... Дело в том, что есть, допустим, гипотетический код на дельфи:
1) Очевидно, что если я оставлю функцию в таком виде - я гарантирую себе весёлую жизнь с утечками памяти, ибо delete\free нигде не вызываются и память по выходу из функции утекает. В итоге - закономерный вопрос: где необходимо освобождать память? Выделять память до вызова функции нет смысла, ибо размер буфера неизвестен; освобождать внутри функции - бессмысленно; выделять внутри, а освобождать после выхода - некрасиво (и есть небезосновательное подозрение, что неправильно)... 2) Как вообще правильно действовать в таких случаях? Использование разнообразных классов типа std::string не предлагать, сам знаю, что они для этого и предназначены, но так же помню, что разнообразные библиотечные функции, работающие с char * - работают вполне корректно и возвращают указатели на вполне валидные буферы. Да, я понимаю, что там используется несколько другой подход - передаются указатели на буферы, где необходимо разместить ответ, но не до конца понимаю, где происходит выделение памяти под эти буферы? (Тот же strcpy - как и где выделяет память под char *strDestination?). Единственный более-менее внятный ответ на похожий вопрос от _hunter'а я увидел у RAN, но и там возник вопрос: а что если память под параметр char* param выделена не через new, а допустим, через malloc (при условии, что я не знаю точно)? В общем, буду признателен, если помимо ответов "ха-ха, ты далпайоп!" и "кури маны, дятел!" (как любит говорить мне мой друг) будут более содержательные разъяснения ![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
||||
|
|||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
ну если посмотреть апишные функции, то как правило им передаётся буфер и размер, а они возвращают количество записанных символов и, если что, количество символов, которые не влезли. По большому счету мне непонятны твои сомнения относительно new или malloc. Ведь полюбому буфер надо выделять перед вызовом и функции побарабану как он получен (хоть массив в стеке). Возвращать из функции имеет смысл если возвращается const char* заранее определененый, а в твоем случае нужно подготовленный буфер передавать и заполнять его. Добавлено через 5 минут и 2 секунды если смотреть твой код
неправильно это. Плохо делать выделение памяти внутри функции. Так ты делаешь вызывающий код зависимым от реализации этой функции. |
|||
|
||||
Walker |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 363 Регистрация: 23.10.2006 Репутация: 1 Всего: 16 |
Хоть сам ещё нахожусь в процессе познания, принять участие в обсуждении интересно. Может вместе найдём истину.
![]() Сразу оговорюсь, я работаю исключительно с С. На первый взгляд складывается ощущение, что при грамотном проектировании такой ситуации возникать просто не должно.
Правильно понимаете. Это чревато следующей ошибкой, которая ловится, зачастую только под отладчиком. Если Вы передаёте адрес как аргумент, то работаете с локальной копией указателя, и внешний мир ничего не знает о выделенном участке. Это будет бесцельная трата памяти. Если же вы используете адрес в качестве возвращаемого значения, то аргументом передавайте размер, Ваша функция будет выполнять роль оболочки над malloc. Напишите обратную функцию - оболочку над free. Библиотечные функции и strcpy в том числе используют именно преопределённые буферы, за выделение и освобождение которых отвечаете Вы. Попробуйте представить иной пример, тогда найдём в открытых исходниках аналог и разберёмся. Пока я такого не встречал. ![]() PS Пока инет глючил, Fazil6 опередил. ![]() Это сообщение отредактировал(а) Walker - 6.6.2008, 10:54 -------------------- "От вчерашних побед остаётся усталость, если завтрашний день не сулит ничего..." |
|||
|
||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
как вариант сначала запрашивать размер буфера, а потом выделять буфер и вызывать GetString, но честно говоря я бы так не делал.
По любому используя С++ лучше контейнер (стандартный или самодельный) вместо char* |
|||
|
||||
Mayk |
|
||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
strcpy не выделяет память. Выделение памяти - это проблемы вызывающего strcpy кода.
курить std::string (c++) и realloc © -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||
|
|||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
вот те раз... приехали... нигде он ее не выделяет. Оба буфера выделены до вызова. |
|||
|
||||
Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
realloc курить сюда. зы! опять мои посты не склеились >ОДНАКО< Это сообщение отредактировал(а) Mayk - 6.6.2008, 10:56 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
Andrey44 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1501 Регистрация: 4.12.2006 Где: На работе Репутация: 2 Всего: 26 |
А можно ли вообще возвращать адрес локальной переменной?
Компилятор по-этому поводу предупреждает! -------------------- ????? ??, ??????? ?????. ![]() |
|||
|
||||
ama_kid |
|
||||||||||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 2 Всего: 95 |
Ага, это если память выделена malloc... А если через new? Делать delete и new заново? Насколько это корректно с точки зрения областей видимости? А если неизвестно - через что выделена память? ![]()
-------------------- самурай без меча подобен самураю с мечом, но только без меча |
||||||||||
|
|||||||||||
MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 52 Всего: 207 |
можно, но не нужно Добавлено через 2 минуты и 47 секунд два варианта 1. отделить функционал от работы с памятью (выделение/освобождение) 2. использовать статический буфер (TLS-буфер в случае многопоточности) -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
Alek86 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
на плюсах это легко:
а не ООП тем и хуже, что ты сам обязан за всем следить |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 2 Всего: 95 |
Да я-то и не против следить, мне собственно и нужно знать - КАК следить? Как правильно будет написать возврат строки из функции?
![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
См аллокаторы в stl. -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
mes |
|
||||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
и в С и в С++ работа по выделению памяти внутри функции не этична
но в С++ можно написать оболочку над буффером (чем с данной точки зрения и является std::string) "стык" между С и С++ приводится к сишнему виду, со всеми вытекающими проблемами.. поэтому имхо вопрос должен относится к чистому С, а не к плюсам
перекосило от конструкции, хотя отработает она без проблем. |
||||
|
|||||
Alek86 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
думаю имелось в виду сделать 2 функции - получение длины данных и заполнение буфера тогда - получил длину - создал буфер - заполнил (GetString) - воспользовался данными - удалил буфер а если получение длины неотделимо от GetString, то или выделяй большой буфер и пускай функция выдает ошибку, если его оказалось недостаточно или уж выделяй внутри функции и возвращай
Добавлено @ 11:59 стандартный прием когда хочется, чтобы функция нужные данные возвращала, и хочется избежать лишних вызовов конструкторов копирования если функция внутри dll находится, то плюсы тут наравне с сями, ибо реализация auto_ptr не специализирована и даже размеры классов для борланда и мелкософтового компилеров могут отличаться Это сообщение отредактировал(а) Alek86 - 6.6.2008, 12:00 |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |