двойное освобождение или повреждение при удалении объекта - PullRequest
4 голосов
/ 01 января 2012

У меня есть класс с именем "Пакет" с этим уничтожением:

class Packet
{
   ...
   RequestPtr req;
   ~Packet()
   {
     if (req && isRequest() && !needsResponse())
        delete req;      
     deleteData();
   }
};

RequestPtr выглядит так:

typedef Request* RequestPtr;
class Request
{
   ...
   ~Request() {} 
}

Проблема в том, что delete req; и, следовательно, ~Request() {} выполнены, я получаю эту ошибку:

*** glibc detected *** double free or corruption (fasttop): 0x0000000002a8a640 ***

Сначала я подумал, что, возможно, req были удалены где-то еще, и когда он хочет выполнить delete req;, очевидно, что req нет. Однако, как вы можете видеть, есть оператор if, который проверяет, определен req или нет. Поэтому, безусловно, когда он хочет удалить req, объект определяется.

Что на самом деле означает эта ошибка?

Ответы [ 3 ]

4 голосов
/ 01 января 2012

Конструктор копирования по умолчанию и оператор присваивания используются в классе Packet, и у вас есть указатель на динамически выделенную память.

Если сделана копия Packet и исходный объект уничтожен, двойное освобождение произойдет при уничтожении второго объекта. Либо реализуйте конструктор копирования и оператор присваивания, либо предотвратите копирование Packet, объявив их private.

Проверка if (req) будет истинной, если req не равен NULL, а не если она уже была освобождена (как указано Мэтом в комментарии к вопросу).

Если вы delete req в каком-либо другом методе класса, вы должны установить req в NULL:

delete req;
req = 0;

Или произойдет двойное освобождение.

Просто отметим, что вызов delete для указателя NULL не имеет никакого эффекта, поэтому следующее безопасно:

delete req;
req = 0;
delete req; // No need to check 'if (req)'
0 голосов
/ 01 января 2012

Я использую этот макрос в классах, отвечающих за очистку других объектов:

// place in a commonly included .h file of yours

#define SAFE_DELETE(p) \
 {if (p != NULL) \
     delete p;\
 p = NULL;}

использование в файле cpp:

~Packet() {
    SAFE_DELETE(req)
}

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

0 голосов
/ 01 января 2012

Правильный способ удаления -

delete req;
req = 0;

, в противном случае req будет являться висящим указателем после удаления.

...