устранение утечек памяти при возврате утечек памяти? - PullRequest
0 голосов
/ 28 октября 2009

Как исправить утечку памяти, когда вы возвращаете из функции саму утечку?

Например, я делаю char* returnMe = new char[24324]; returnMe - это то, что заканчивается возвращением из функции. Как вы объясняете эту утечку памяти? Как вы уничтожаете его, как только он был возвращен? У меня есть некоторые правила управления памятью, которые генерируют ошибки времени выполнения для утечек памяти, чтобы остановить это, поэтому я не могу игнорировать это.

Орр, я дурак, и это не утечка, подразумевая, что утечка в другом месте?

Ответы [ 7 ]

13 голосов
/ 28 октября 2009

Это не утечка, если вы ее вернете (ну, это не ваша утечка).

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

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

3 голосов
/ 28 октября 2009

Вы все еще можете delete[] указатель returnMe даже после его возвращения. Это не утечка памяти, если вы не забудете удалить returnMe.

2 голосов
/ 28 октября 2009

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

Когда буфер возвращается, он контролируется клиентским кодом. В целом, для твердого программирования хорошая идея, чтобы распределение / освобождение происходило на одном уровне. Это означает, что если у вас есть подпрограмма, которая возвращает буфер, у вас должна быть соответствующая подпрограмма, которая освобождает его, даже если код клиента может вызвать delete [].

Например: предположим, у вас есть этот код

char *mylib_gimmeh_buffer() {
    char* returnMe = new char[24324];
    return returnMe;
}

Для симметрии вы должны иметь также

char *mylib_free_buffer(buffer) {
    delete[] buffer;
}

Теперь ваш клиентский код должен вести себя так

buf = mylib_gimmeh_buffer();
/* do something with buf */
mylib_free_buffer(buf);

если ваш клиент делает что-то подобное

mylib_gimmeh_buffer(); // just for fun

или как это

buf = mylib_gimmeh_buffer();
/* do something with buf */
/* never call mylib_free_buffer() */

тогда есть утечка памяти

1 голос
/ 28 октября 2009

Хотя возможно иметь функцию, которая выделяет память и возвращает указатель на нее, она действительно подвержена ошибкам ... каждый раз, когда кто-то вызывает эту функцию, он должен знать, что функция будет выделять память от их имени и они должны знать, что они несут ответственность за освобождение этой памяти, и они должны знать соответствующий способ освобождения памяти, когда они закончили с этим (delete? delete []? free ()? Something else?), и необходимо убедиться, что free происходит ровно один раз, во всех случаях, и они должны быть уверены, что никогда не разыменовывать указатель после освобождения.

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

К счастью, в C ++ есть лучшие способы сделать это, которые вызывающему абоненту намного сложнее испортить. Например, вместо возврата необработанного указателя вы можете вернуть shared_array , который автоматически удалит выделенную память, когда последний указатель на нее исчезнет. Таким образом, никто не должен думать об управлении памятью, оно «просто работает».

Как только вы привыкнете к этому, вы никогда не захотите возвращаться!

1 голос
/ 28 октября 2009

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

void function() {
    char *to_free = NULL;
    //to_free does not need to be freed yet

    to_free = function_that_uses_new_to_set_return();

    //to_free now must be freed if that function worked
    if (to_free != NULL) delete[] to_free;
}
1 голос
/ 28 октября 2009
char* function()
{
   char* returnMe = new char[24324];
   return returnMe;
}

int main()
{
   char* pGetReturnME = function();
   delete [] pGetReturnME;
}

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

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

0 голосов
/ 28 октября 2009

Одним из решений является возврат памяти способом, который трудно утечь. Например. вернуть его как boost::shared_ptr с пользовательским средством удаления (так как вам нужно удалить []). Теперь вызывающему абоненту требуются усилия для утечки.

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