c ++ проблема с указателем удаления, все равно доступ к данным

Я действительно не понимаю, почему этот указатель доступен … любая помощь была оценена

#include  class Wicked{ public: Wicked() {}; virtual ~Wicked() {}; int a; int b; }; class Test { public: Test() {}; virtual ~Test() {}; int c; Wicked * TestFunc() { Wicked * z; c = 9; z = new Wicked; z->a = 1; z->b = 5; return z; }; }; int main() { Wicked *z; Test *t = new Test(); z = t->TestFunc(); delete z; delete t; // why can I set 'z' when pointer is already destroyed? z->a = 10; // why does z->a print 10? std::cout <a <c exist and print correct value? std::cout <c << std::endl; //------------------------------------------------------ int * p = new int; *p = 4; // this prints '4' as expected std::cout << *p << std::endl; delete p; // this prints memory address as expected std::cout << *p << std::endl; return 0; } 

Удаление указателя не обнуляет память, потому что для этого потребуются циклы CPU, и это не то, о чем говорит C ++. У вас есть висячий указатель и, возможно, тонкая ошибка. Подобный код иногда может работать в течение многих лет только в случае сбоя в какой-то момент в будущем, когда некоторые незначительные изменения происходят где-то еще в программе.

Это хорошая причина, по которой вы должны указывать NULL out, когда вы удаляете память, на которую указывают, таким образом, вы получите немедленную ошибку, если попытаетесь разыменовать указатель. Иногда также рекомендуется очистить память, указанную с помощью функции memset (). Это особенно верно, если указанная память содержит что-то конфиденциальное (например, пароль незашифрованного текста), от которого вы не хотите, чтобы другие пользователи, с которыми пользователь сталкивался, имели доступ к частям вашей программы.

Это неопределенное поведение . Все может случиться. На этот раз тебе повезло. Или, возможно, не повезло, так как было бы предпочтительнее получить ошибку времени выполнения! В следующий раз, возможно, вы получите ошибку времени выполнения.

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

C ++ не остановит вас от записи в произвольное место в памяти. Когда вы выделяете память new или malloc , C ++ обнаруживает неиспользуемое пространство в памяти, отмечает его как выделенное (чтобы его случайно не раздавали) и дает вам свой адрес.

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

Вот

 // why can I set 'z' when pointer is already destroyed? z->a = 10; 

z все еще указывает на ячейку памяти.
Но он больше не блуждает с тобой. Вы передали его для удаления и сказали, что позаботились об этом указателе. То, что это делает, больше не является вашей проблемой. Это нравится, когда вы продаете свой автомобиль; он все еще существует, но его не твой, поэтому открытие двери и поиск в ней возможно, но это может привести к тому, что полиция арестовывает вас.

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

delete z; просто освобождает память z указывающую на нее, она не уничтожает сам указатель.

Таким образом, z становится диким указателем .

Поскольку удаление блока памяти не приводит к нулю значение всех указателей, указывающих на него. Удаление памяти просто отмечает, что память доступна для других целей. Пока это не произойдет, память может показаться неповрежденной, но вы не можете рассчитывать на нее, а на некоторых комбинациях компилятора / времени выполнения / архитектуры ваша программа будет вести себя по-другому – она ​​может даже сбой.