#include <iostream>
using namespace std;
int main() {
int *p1;
p1 = new int;
int *p2;
p2 = new int;
p2 = p1; // what happens here?
*p1=5;
cout << "pointer 2 is " << *p2 << endl << *p1 << endl; // both give out 5
delete p1; // what happens to p2 ?
cout << "pointer 2 is " << *p2 << endl;
delete p2;
return 0;
}
Что происходит, когда я удаляю объект-указатель p1? На что сейчас ссылается указатель p2? Может кто-нибудь объяснить? Спасибо за помощь
Важный момент: указатель — это переменная, которая содержит адрес и может использоваться для доступа к объекту по этому адресу. В остальном это точно так же, как и любая другая переменная, поэтому p2 = p1;
заменяет адрес, сохраненный p2
, на адрес, сохраненный p1
.
@ Брайан: Спасибо за ссылку. Это объяснение является очень хорошей аналогией управления памятью. Это было полезно
На что сейчас ссылается указатель p2?
Ничего. Он болтается. Он указывал на то же самое, на что указывал p1
, но вы удалили это.
Следовательно, ваш *p2
сломан, как и ваш delete p2
; они оба имеют неопределенное поведение.
Вы также слили второй new int
, потому что p2
раньше указывал на него, но перестал делать это, когда вы написали p2 = p1
(вместо этого вы изменили его, чтобы он указывал на первый new int
, как это делает p1
), и нет другого способа сослаться на него. .
Хорошая диаграмма. Я бы предложил также включить последнее cout << *p2
заявление в огонь
@RemyLebeau Хорошая идея
@Астероиды с крыльями, боже мой! это было замечательно. По-видимому, мой код имеет два греха: утечка памяти, попытка удалить висячий объект. Мне понравилась огненная часть
p2 = p1; // what happens here?
Вы просто копируете значение (указанный адрес памяти) p1
в p2
. Это ничем не отличается от этого:
int i1, i2;
i1 = 12345;
i2 = i1;
Однако, поскольку рассматриваемое значение в адресе памяти, выделенном с помощью new
, теперь у вас есть утечка памяти, поскольку вы потеряли свой единственный указатель на 2-й выделенный int
, на который ранее указывал p2
. Теперь p1
и p2
указывают на 1-й int
в памяти.
cout << "pointer 2 is " << *p2 << endl << *p1 << endl; // both give out 5
Да, потому что p1
и p2
указывают на один и тот же адрес памяти.
delete p1; // what happens to p2 ?
Здесь ничего не происходит с p2
, он по-прежнему указывает на тот же адрес памяти, что и раньше. p1
и p2
являются независимыми переменными, поэтому изменение одной не влияет на другую. Но delete
освободил 1-й int
, который был сохранен по адресу памяти, на который указывают p1
и p2
, поэтому теперь они оба являются обособленными указателями на недействительную память. Поскольку вы не используете p1
после этого, это нормально для p1
, но для p2
следующие утверждения:
cout << "pointer 2 is " << *p2 << endl; delete p2;
Вызовет Undefined Behavior, потому что вы обращаетесь к недопустимой памяти через оборванный p2
. Чтение может успешно вернуть устаревшие данные, которые все еще присутствуют по адресу памяти, или оно может вернуть мусор, или может произойти сбой. delete
почти наверняка выйдет из строя, так как память уже была освобождена ранее, но и это не гарантировано. Undefined Behaivor просто не определен, так что буквально все может случиться.
Спасибо за подробное объяснение того, что пошло не так, особенно при попытке доступа к объекту, на который указывает p2. Это было сообщение об ошибке, которое я получил при выполнении программы: «free(): обнаружен двойной свободный доступ в tcache 2 Aborted». Теперь я понимаю, что произошло.
Вы можете найти этот вопрос полезным для понимания того, что такое указатели. Этот сценарий рассматривается под заголовком «утечка памяти».