Освобождение памяти у звонящего или вызываемого? - PullRequest
4 голосов
/ 12 октября 2011

Функция (скажем, «fun ()») выделяет память и возвращает указатель на выделенную память.Как я должен убедиться, что эта память освобождена.Я не могу немедленно выпустить его в функции "fun ()", так как он возвращается вызывающей стороне.А что если fun () является частью библиотеки?Чья это ответственность за освобождение памяти.В случае fopen () память освобождается функцией fclose ().Но в моем случае «fun ()» вызывается неоднократно.Поэтому я не могу дождаться конца, чтобы освободить память.

Ответы [ 6 ]

5 голосов
/ 12 октября 2011

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

Например:

std::shared_ptr<TypePointedTo> data = fun();

Таким образом, когда shared_ptr разрушает его, он будет автоматическиосвободите память для вас.

Или, если это массив, который вы хотите вернуть, используйте вектор, опять же, это автоматически освободит память для вас:

std::vector<BYTE> data = fun();

Прочитайте отличные комментарии,std :: unique_ptr может быть лучше, чем std :: shared_ptr во многих сценариях.

Если это C ... см. другие ответы!

5 голосов
/ 12 октября 2011

Ниже приведен ответ для C, опубликованный до того, как OP признался в использовании C ++. На этом языке используйте RAII и умные указатели, как рекомендовано другими.

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

Если требуется дополнительная очистка, то предлагается free, или такая очистка может потребоваться в будущих версиях библиотеки, тогда вы должны предложить функцию очистки (как stdio делает с fclose) что делает освобождение.Если вы не можете предсказать, может ли понадобиться дополнительная очистка в будущем, будет хорошей идеей предположить, что это произойдет в какой-то момент.Упаковка free дешева.

Думайте об этом как о форме симметрии: если клиент получает ресурс (объект) из библиотеки, то в конечном итоге он отвечает за передачу его обратно в библиотеку для утилизации:

void use_the_foo_library()
{
    Foo *f = make_foo();
    if (f == NULL)
        ERROR();

    foo_do_bar(f);
    foo_do_baz(f);

    foo_destroy(f);
}

, где в foolib 1.0, foo_destroy - это просто

void foo_destroy(Foo *p)
{
    free(p);
}

, но в версии 2.0 оно может увеличиться до

void foo_destroy(Foo *p)
{
    fclose(p->logfile);
    free(p);
}

и т. Д.Этот стиль соответствует шаблону непрозрачный указатель .Это также дает вам свободу замены malloc и free в любой точке специальным распределителем памяти, таким как распределитель пула , без необходимости изменения любого клиентского кода.

2 голосов
/ 12 октября 2011

В C ++ вы бы возвращали умный указатель, который четко указывает (и обеспечивает), что право собственности было передано вызывающей стороне, и позволяет вызывающей стороне выбирать, что с ним делать.Это также обеспечивает безопасность исключений, предотвращая утечку памяти, если исключение (или просто раннее возвращение функции) приводит к тому, что единственный указатель на ресурс выходит из области видимости.

В C ++ 03, std::auto_ptrлучший выбор здесь;в C ++ 11 это не рекомендуется в пользу std::unique_ptr.

2 голосов
/ 12 октября 2011

C Решение:

А что если fun () является частью библиотеки?

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

РЕДАКТИРОВАТЬ:

C ++ Решение:

Поскольку вы редактировали, чтобы сказать, что вы используете C ++, возможно, лучше использовать интеллектуальные указатели (std::tr1::shared_ptr) для автоматической обработки памяти за вас.

Если по какой-то причине вы не можете использовать умные указатели, лучше использовать std::vector.

0 голосов
/ 12 октября 2011

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

Вы можете предоставить метод cleanUp () для вызова и очистить память, но он все еще зависит от вызывающей стороны, и вы добавите сложности, когда он должен вызываться.*

Единственная реальная альтернатива - настроить умный механизм «подсчета ссылок», такой как в Objective-C (см. Выпуск и авто-выпуск).

0 голосов
/ 12 октября 2011

Если вам нужна память вне вызываемого абонента, вполне очевидно, что она ответственна за освобождение памяти, поскольку вы не можете реально освободить ее в вызываемом абоненте.Это то же самое, что new и delete - вы просто должны помнить, чтобы освободить эту память.Убедитесь, что вы задокументировали тот факт, что вызывающий абонент отвечает за управление памятью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...