Почему плохая память в функции и ее освобождение снаружи - плохая идея? - PullRequest
12 голосов
/ 31 марта 2010

если это плохая идея, как выделить память в функции?

Ответы [ 5 ]

22 голосов
/ 31 марта 2010

Это не «плохая идея», а скорее «иногда плохая идея», что можно сказать о многих идеях в программировании.

Кстати, выделение памяти внутри функции и освобождение ее наружу может быть общей схемой проектирования. Рассмотрим:

// hashtable is a typedef-ed pointer type
hashtable ht = hashtable_new();
// .. do something with hashtable
hashtable_free(ht);

ht был выделен в функции hashtable_new и выпущен за ее пределы, но вы увидите этот шаблон снова и снова во многих хороших кодах Си.

Однако он показывает, как одна и та же логическая единица (ADT хеш-таблицы) заботится о распределении и перераспределении. Это имеет большой смысл - потому что тот, кто знает, как распределять, знает лучше, как освобождать. Распределение и освобождение в различных логических единицах чаще всего является плохой идеей.

9 голосов
/ 31 марта 2010

На этот вопрос легче всего ответить, если мы перевернем его:

  • Почему было бы неплохо, если бы каждый объект malloc 'd в функции также был free d в той же функции?

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

А что если функция вызывает malloc, а не free? Тогда должны быть правила о том, кто обязан освобождать память, когда это разрешено делать и когда требуется . Эти правила становятся частью интерфейса функции , и любой, кто вызывает функцию, должен либо обеспечить соблюдение правил, либо следовать им, либо, возможно, навязывать аналогичные правила для ее вызывающей (ей) программы и т.д. , Явное управление памятью добавляет сложности интерфейсам , и чем сложнее интерфейсы, тем легче допустить ошибку, которая приводит к ошибке памяти & mdash; а в C ошибка памяти может привести к аварийному завершению вашей программы.

К сожалению, иногда необходимо иметь объект, который (a) должен быть выделен во время выполнения и (b) должен пережить активацию функции, которая его выделяет. В таких случаях, даже если кажется, что это может быть плохой идеей, у нас нет другого выбора, кроме как сделать распределение, усложнить интерфейс и потребовать от вызывающего абонента правильного управления объектом.

(Один из более простых случаев - когда объект выделяется во время выполнения, но ему разрешено жить вечно. Но вы должны ограничить количество таких объектов, иначе у вас не хватит места.)

3 голосов
/ 31 марта 2010

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

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

Просто будьте осторожны с вашим дизайном. Сопоставляйте malloc с free каждый раз, и у вас не будет утечек памяти.

2 голосов
/ 31 марта 2010

Неплохая идея, если вы просто будете поддерживать ее в своем собственном стиле.

Хорошим подходом является передача выделенной памяти вызывающей стороне, которая затем может освободить ее, когда это будет сделано. Примерно так:

void my_new(char **obj) {
    *obj = malloc(somesize);
}

и затем вызовите это из вашей функции следующим образом:

char *obj;

my_new(&obj);

/* work on obj */

free(obj)
0 голосов
/ 01 марта 2018

Существуют определенные шаблоны для управления памятью:

  1. для выделения памяти внутри функции, освобождения ее снаружи, когда она истекает в срок
  2. чтобы удерживать указатель в функции, где вызывается malloc, и освобождать его после истечения срока действия, как сказал joveha.

Имейте в виду последовательность, иначе это может легко привести к утечке памяти или висящим указателям.

...