Удаление динамического выделения памяти

Если бы я динамически выделял место в памяти для объекта int следующим образом:

int *x = new int;

После того, как с этим покончено и я хочу освободить память в куче, я сделаю следующее:

delete x;

Теперь, если бы я не сделал следующее:

x = NULL;

Будет ли x указывать на другой адрес? ОБНОВЛЕНИЕ: another вместо many

Допустим, я не сделал x = NULL и сделал другое delete x;, что произойдет?


person Simplicity    schedule 29.01.2011    source источник
comment
parashift.com/c%2B% 2B-faq-lite/freestore-mgmt.html#faq-16.2   -  person Cody Gray    schedule 29.01.2011


Ответы (6)


  1. Все, что вы делаете с x (кроме = NULL - что, по моему мнению, является плохой практикой) после его удаления, не определено.
  2. двойное удаление = катастрофа.

Примечание: некоторые системы выполнения защитят вас от очень простых случаев двойного удаления. В зависимости от деталей, вы можете быть в порядке, если вы работаете в одной из этих систем, и если никто никогда не развертывает ваш код в другой системе, которая обрабатывает вещи по-другому, и если вы удаляете что-то, что не имеет деструктора, и если вы не делаете ничего существенного между двумя удалениями, и если никто никогда не изменит ваш код, чтобы сделать что-то значимое между двумя удалениями, и если ваш планировщик потоков (над которым вы, вероятно, не имеете контроля!) не переключает потоки между два удаления и если, и если, и если. Итак, вернемся к Мерфи: раз что-то может пойти не так, так оно и будет, и пойдет не так в самый неподходящий момент.

https://isocpp.org/wiki/faq/freestore-mgmt

person David Titarenco    schedule 29.01.2011

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

person Jerry Coffin    schedule 29.01.2011

Это вызовет неопределенное поведение. Если вы не сделаете x=NULL, то x будет указывать на недопустимое место в памяти, которое, если вы попытаетесь использовать его, вызовет неопределенное поведение.

person Asha    schedule 29.01.2011
comment
Но когда я делаю delete, разве я не удаляю сам pointer? Как это, как вы говорите: «Если вы не сделаете x = NULL, тогда x будет указывать на недопустимую ячейку памяти»? Спасибо - person Simplicity; 29.01.2011
comment
@ user588855: Допустим, x был 0x11111111 перед удалением. Итак, когда вы делаете delete x;, эта ячейка памяти свободна. Но поскольку вы не установили для x значение NULL, оно по-прежнему имеет значение 0x11111111, которое является освобожденной ячейкой памяти. Попытка чтения/записи в это место с использованием *x или x-> приведет к неопределенному поведению. - person Asha; 29.01.2011

тип:

int main(){
  int* i = new int;
  std::cout << i << std::endl;
  delete i;
  std::cout << i << std::endl;
  delete i;
}

результат:

0x8e19008

0x8e19008

** Обнаружен glibc ** ./a.out: двойное освобождение или повреждение (fasttop): 0x08e19008 *

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

person thorsten müller    schedule 29.01.2011
comment
Это последнее предложение не обязательно верно: некоторые компиляторы защитят вас от этого, так что это может казаться работоспособным. Но это все еще неопределенное поведение, и это все еще плохая идея. Тестирование - неправильный способ получить ответ здесь. - person Cody Gray; 29.01.2011
comment
@Code Grey: это не тестирование, это демонстрация. То, что первое предложение не обязательно верно, поэтому я сказал, что может зависеть от окружающей среды. - person thorsten müller; 29.01.2011

вызов удаления в уже удаленной памяти приведет к неопределенному поведению. Как правило, ваша программа будет аварийно завершать работу.

После удаления x, куда он будет указывать, это "зависит от компилятора". Большинство компиляторов просто позволяют ему указать, где он был до вызова удаления. Но этот адрес памяти больше недействителен и, следовательно, не должен вызываться.

По этой же причине «удалить это» следует использовать очень разумно и осторожно, если это вообще необходимо. :-)

person Viren    schedule 29.01.2011
comment
Когда вы говорите: calling delete on already deleted memory will cause undefined behaviour.. Разве не удаляется pointer, а не memory? Спасибо - person Simplicity; 29.01.2011
comment
@user: ни один из них не удаляется сам по себе. Память освобождается, а это значит, что ваша программа сообщает операционной системе: окей, спасибо за кусок памяти, с ним покончено! и ваша программа больше не имеет доступа к нему для чтения/записи. - person David Titarenco; 29.01.2011

Второе удаление не определено.

Кстати, есть инструменты для обнаружения двойного удаления. Один из лучших — Valgrind.

person vz0    schedule 29.01.2011