«Удалить указатель» означает просто «* указатель = 0»? - PullRequest
5 голосов
/ 31 января 2012
# include <iostream>

int main()  
{  
using std::cout;
int *p= new int;

*p = 10;
cout<<*p<<"\t"<<p<<"\n";
delete p;
cout<<*p<<"\t"<<p<<"\n";

return 0;

}

Выход:
10 0x237c010
0 0x237c010

Здесь после удаления p, почему указатель p сохраняет свое значение? Не удаляет освобождает ли указатель p?
Что именно означает «освобождение указателя»?
«Удалить p» означает просто «* p = 0»? (Что видно из вывода)

Ответы [ 5 ]

6 голосов
/ 31 января 2012

Здесь после удаления p, почему указатель p сохраняет свое значение?

Так устроен язык.Если вы хотите, чтобы указатель, который вы держите, обнулялся, вам нужно присвоить ему ноль самостоятельно.Указатель p - это еще один фрагмент памяти, отдельный от выделения / объекта, на который он указывает.

Не удаляет освобождает указатель p?

Он вызываетДеструктор объекта и возвращает память в систему (как бесплатно).Если это массив (delete[]), будут вызваны деструкторы для всех элементов, а затем будет возвращена память.

Что именно означает «освобождение указателя»?

Если вам нужен фрагмент памяти из системы, вы выделяете его (например, с помощью new).Когда вы закончите использовать его, вы вернете его, используя соответствующий вызов free / delete.Это ресурс, который вы должны вернуть.Если вы этого не сделаете, ваша программа будет течь (и никто не хочет этого).

2 голосов
/ 31 января 2012

Чтобы понять, что означает освобождение памяти, вы должны сначала понять, что означает выделение памяти.Далее следует упрощенное объяснение.

Существует память.Память - это большой кусок материала, к которому вы можете получить доступ.Но так как это глобально, вам нужно каким-то образом разделить его.Какой-то способ определить, кто может получить доступ к каким частям памяти.Одна из систем, которая управляет распределением памяти, называется «кучей».

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

То, что делает new int, в два раза.Во-первых, он обращается к системе кучи и говорит: «Я хочу кусок памяти, подходящий для хранения int».Он возвращает указатель именно на это: часть кучи, в которую вы можете безопасно сохранить и получить ровно одно значение типа int.

Теперь вы гордый владелецодной int ценности памяти.Куча гарантирует , что до тех пор, пока соблюдаются ее правила, все, что вы там поместите, будет сохраняться до тех пор, пока вы явно не измените его.Это завет между вами и всемогущей кучей.

Другая вещь, которую new int делает, инициализирует эту часть кучи значением int.В этом случае он инициализируется по умолчанию, поскольку не было передано никакого значения (new int(5) инициализировало бы его значением 5).

С этого момента вам по закону разрешено хранить ровно один int вэтот кусок памяти.Вам разрешено восстановить int, хранящиеся там.И вам разрешено сделать еще одну вещь: сообщить куче, что вы закончили использовать эту память.

Когда вы вызываете delete p, происходят две вещи.Во-первых, p деинициализирован.Опять же, потому что это int, ничего не происходит.Если бы это был класс, его деструктор был бы назван.

Но после этого delete выходит в кучу и говорит: «Эй, куча: помните этот указатель на int, который вы мне дали? Iс этим покончено. "Система кучи может делать все, что захочет.Возможно, это очистит память, как это делают некоторые кучи в сборках отладки.Однако в сборках релиза память может не очищаться.

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

После того, как вы повеселились, вы вернули его в кучу.И вот здесь вступает в силу контракт. Когда вы говорите delete p, для любой объект p, вы говорите следующее:

Я торжественно клянусь не трогать этоадрес памяти снова!

Теперь куча может вернуть вам этот адрес памяти, если вы снова вызовете new int.Это может дать вам другой.Но у вас есть доступ только к памяти, выделенной кучей в течение времени между new и delete.

Учитывая это, что это значит?

delete p;
cout << *p << "\t" << p << "\n";

На языке C ++ это называется "неопределенным поведением".В спецификации C ++ есть много вещей, которые заявлены как «неопределенные».Когда вы запускаете неопределенное поведение , может произойти все что угодно! *p может быть 0. *p может быть значением, которым оно было раньше.Выполнение *p может привести к сбою вашей программы.

Спецификация C ++ - это контракт между вами и вашим компилятором / компьютером.Он говорит, что вы можете сделать, и он говорит, как реагирует система.«Неопределенное поведение» - это то, что происходит, когда вы нарушаете контракт, когда вы делаете что-то, что спецификация C ++ говорит, что вы не должны этого делать.В этот момент все может произойти.

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

Вы нарушили правила.И вы должны страдать от последствий.

Так что нет, delete p не является эквивалентом *p = 0.Последнее просто означает «установить 0 в память, на которую указывает p».Первый означает «я закончил использовать память, указанную p, , и я не буду использовать ее снова , пока вы не скажете мне, что я могу».

1 голос
/ 31 января 2012

Здесь после удаления p, почему указатель p сохраняет свое значение? Не удаляет освобождает ли указатель p?

Освобождает память, на которую указывает указатель (после вызова любого подходящего деструктора). Значение самого указателя не изменяется.

Что именно подразумевается под «освобождением указателя»?

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

Означает ли "удаление p" просто "* p = 0"? (Что видно из вывода)

Нет. Система не имеет для записи чего-либо в освобожденную память, а если она что-то записывает, ей не нужно записывать 0. Однако система обычно должна каким-то образом управлять этой памятью, и это может фактически записать в область памяти, на которую указывает указатель. Кроме того, только что освобожденная память может быть выделена для чего-то другого (и в многопоточном приложении это может произойти до того, как операция delete даже вернется). Новый владелец этого блока памяти, конечно, может записать в эту память все, что захочет.

Указатель, который указывает на освобожденный блок памяти, часто называют «висящим» указателем. Ошибка разыменования висячего указателя (для чтения или записи). Иногда вы увидите, как код сразу назначит указатель NULL или 0 сразу после удаления указателя, иногда используя макрос или шаблон функции, который одновременно удаляет и очищает указатель. Обратите внимание, что это не исправит все ошибки с висячими указателями, так как другие указатели могли быть установлены для указания на блок памяти.

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

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

(Обратите внимание, что на самом деле это не так, поэтому возьмите его с крошкой соли.)

Внутри реализации new он хранит список всей доступной памяти, когда вы говорите "int * p= новый int; "он вырезал блок размером с int из списка доступной памяти и дал его вам.Когда вы запускаете "удалить р;"он возвращается в список доступной памяти.Если бы ваша программа вызывала new 30 раз, не вызывая delete вообще, вы получили бы 30 различных кусков int размера из new.Если вы вызвали new, то удалите 30 раз подряд, вы можете (но не обязательно) получить один и тот же блок размером с int.Это потому, что вы сказали, что больше не используете его, когда вызываете delete, и поэтому new может свободно использовать его.

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

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

delete p просто освобождает память, выделенную во время вызова оператору new.Он не изменяет значение указателя или содержимое освобожденной памяти.

...