C ++ массив указателей утечек памяти - PullRequest
2 голосов
/ 03 ноября 2011

В моем классе у меня есть динамически распределенный массив указателей.Мое объявление:

 array = new Elem* [size];
 for (int i = 0; i < size; i++) {
    array[i] = NULL;
 }

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

Главный вопрос заключается в том, как правильно освободить массив.Если я использую только:

for (int i = 0; i < size; i++) {
   delete array[i];
}

Valgrind сообщает о 1 не освобожденном блоке, который прослеживается до строки, где 'array = new Elem * [size];'состояния.

С другой стороны, если я добавлю к предыдущему коду:

delete array;

То, что я считаю правильным, valgrind сообщает о 0 не освобожденных блоках, что идеально, НО это сообщает

Mismatched free() / delete / delete []

точно в той строке, где 'delete array;'является.Я тоже попробовал 'delete [] array', но это тоже просто "1 не освобожденный блок"!Если бы кто-нибудь смог мне правильно объяснить это, это было бы очень ценно.

РЕДАКТИРОВАТЬ: Таким образом, использование:

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

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

array = new Elem* [size];

.

EDIT2: Я тоже это решил, спасибо за ваш изнурительный вклад !!

Ответы [ 4 ]

8 голосов
/ 03 ноября 2011

Вам нужно:

delete [] array;

Поскольку это массив.

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

Редактировать: Это заслуживает более подробного объяснения.

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

Elem ** single = new Elem*;    // pointer to one pointer
single[0] = new Elem;          // OK
single[1] = new Elem;          // runtime error, but not compile time

Elem ** array = new Elem* [2]; // pointer to array of pointers
array[0] = new Elem;           // OK
array[1] = new Elem;           // OK

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

delete single;
delete [] array;

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

7 голосов
/ 03 ноября 2011

Вы должны освободить все в массиве (если он размещен динамически), а затем освободить сам массив.

for (int i = 0; i < size; i++) { // only free inside if dynamically allocated - not if just storing pointers
   delete array[i];
}
delete[] array; // necesarry
5 голосов
/ 03 ноября 2011

Синтаксис для удаления массива выглядит так:

delete[] array;

Ваш цикл for для удаления объектов, на которые указывают элементы массива, вполне подходит. Удаление самого массива является единственной проблемой. Вам нужно и цикл for, а затем delete[] для удаления самого массива.

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

Я подозреваю, что вы пытались использовать цикл for или delete[], но не оба вместе. И если после этого у вас все еще есть утечки или ошибки, вам нужно будет показать нам код, который выделяет указатели, которые являются элементами массива.


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

2 голосов
/ 03 ноября 2011

В этом случае вам нужно оба .

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

Вы звоните delete ровно один раз за каждый раз, когда вы набрали new.

Обратите внимание, чтохотя вам необходимо вызвать delete[] array здесь (поскольку вы выделили его с помощью new[]), оператор delete[] не вызывает деструкторы объектов, на которые указывают элементы массива.Это связано с тем, что оператор delete[] вызывает деструкторы для объектов в массиве, а ваш массив содержит указатели, но не объекты.Сами указатели не имеют деструкторов.

...