если это плохая идея, как выделить память в функции?
Почему malloc память в функции и освобождение ее снаружи - плохая идея?
Ответы (5)
Это не «плохая идея», а скорее «иногда плохая идея», что можно сказать о многих идеях в программировании.
Между прочим, выделение памяти внутри функции и освобождение ее снаружи может быть распространенным шаблоном проектирования. Рассмотреть возможность:
// hashtable is a typedef-ed pointer type
hashtable ht = hashtable_new();
// .. do something with hashtable
hashtable_free(ht);
ht
был выделен в функции hashtable_new
и освобожден вне ее, тем не менее, вы будете видеть этот шаблон снова и снова во многих хороших C-кодах.
Однако он показывает, как одна и та же логическая единица (АТД хэш-таблицы) заботится о выделении и освобождении памяти. В этом есть большой смысл, потому что тот, кто знает, как распределять, лучше всех знает, как освобождать. Выделение и освобождение в разных логических единицах чаще всего является плохой идеей.
На этот вопрос легче всего ответить, если мы изменим его:
- Почему может быть хорошей идеей, если каждый объект
malloc
d в функции такжеfree
d в той же функции?
Ответ таков: утечек памяти или оборванных указателей не будет, и этот ценный результат достигается без участия какой-либо другой функции. В результате легче получить правильный код, а функция имеет простой интерфейс.
А что, если функция вызывает malloc
, но не free
? Затем должны быть правила о том, кто обязан освобождать память, когда это разрешено и когда это требуется. Эти правила становятся частью интерфейса функции, и любой, кто вызывает функцию, должен либо убедиться, что правила или соблюдаются, либо, возможно, наложить аналогичные правила на его вызывающего(ых), и скоро. Явное управление памятью усложняет интерфейсы, и чем сложнее интерфейсы, тем легче сделать ошибку, которая приведет к ошибке памяти, а в C ошибка памяти может привести к сбою программы.
К сожалению, иногда необходимо иметь объект, который (а) должен быть выделен во время выполнения и (б) должен пережить активацию выделяющей его функции. В таких случаях, хотя это может показаться плохой идеей, у нас нет другого выбора, кроме как выполнить выделение, усложнить интерфейс и потребовать от вызывающего объекта корректного управления объектом.
(Один из более простых случаев — это когда объект выделяется во время выполнения, но ему разрешено жить вечно. Но вы должны ограничить количество таких объектов, иначе у вас закончится место.)
Это неплохая идея, если вы просто будете придерживаться своего собственного стиля.
Хорошим подходом является передача выделенной памяти вызывающей стороне, которая затем может освободить ее, когда это будет сделано. Что-то вроде этого:
void my_new(char **obj) {
*obj = malloc(somesize);
}
а затем вызовите это из своей функции следующим образом:
char *obj;
my_new(&obj);
/* work on obj */
free(obj)
Не обязательно плохо выделять память в функции. Вы просто должны убедиться, что очистить его должным образом.
Проблема в том, что вы можете потерять эту возможность, как только покинете область действия функции.
Просто будьте осторожны с вашим дизайном. Сопоставляйте malloc с free каждый раз, и утечек памяти не будет.
Существуют определенные шаблоны для управления памятью:
- выделить память внутри функции, освободить ее снаружи, когда она переживет положенное время
- чтобы удерживать указатель в функции, где вызывается malloc, и освобождать его после истечения срока его действия, как сказал joveha.
Помните о согласованности, иначе это легко приведет к утечке памяти или оборванным указателям.