Почему я должен дважды вызывать «delete», если у меня есть два указателя в одной и той же памяти? - PullRequest
1 голос
/ 25 апреля 2019

Я выделил память кучи переменной указателя 'k' с помощью new и скопировал ее в другую переменную указателя 'd'.

В этом случае я думал, что эти две переменные указывают на одну и ту же память, поэтому "delete" эта память была необходима только для одной переменной;все, что 'k' или 'd'.Однако когда я сделал delete k, 'k' и 'd' еще указывали на память.

Итак, я сделал delete d, и появился Abort trap 6 error.

Вот мой тестовый код.

int* k;
k = new int(5);

int* d = k;

cout<<"d's : "<<d<<endl;
cout<<"k's : "<<k<<endl;

delete d;

cout<<"d's : "<<d<<endl;
cout<<"k's : "<<k<<endl;

delete k;

cout<<"d's : "<<d<<endl;
cout<<"k's : "<<k<<endl;

Результат:

d's: 0x7fbb56c02ae0
k's: 0x7fbb56c02ae0
d's: 0x7fbb56c02ae0
k: 0x7fbb56c02ae0

Прерывание прерывания: 6

Я ожидал, что доступ к 'k' и 'd' сделал segment error после того, как я сделал delete d, потому что яПамять удалил!

Чего мне не хватает, может кто-нибудь мне помочь с этим?

Ответы [ 2 ]

3 голосов
/ 25 апреля 2019

Однако, когда я сделал delete k, k и d еще указывают на память.

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

Вот почему иногда люди устанавливают указатель на nullptr после delete -из этого.В вашем случае это спасло бы вас от неопределенного поведения:

delete d;

d = nullptr;
k = nullptr; // Both must be re-assigned

delete k; // Ok, delete on a nullptr is a no-op
1 голос
/ 25 апреля 2019

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

Таким образом, когда вы delete указываете, указатель по-прежнему будет указывать на те же байты в физической памяти после факта , но вам больше не разрешено их использовать . Если вы это сделаете, все может случиться. Это относится даже к самому указателю: любой указатель, указывающий на delete d памяти, больше не должен касаться, он сразу же становится недействительным.

Если вы используете указатель после того, как он был delete d, он может работать правильно. Или вы можете потерпеть крах. Или вы можете получить доступ к другому объекту памяти, который был создан с использованием тех же физических байтов памяти. Вы просто не знаете, что на самом деле произойдет .

Таким образом, ваша первоначальная идея верна: delete нужен только один из двух указателей, другой не следует трогать после факта:

int* k;
k = new int(5);

int* d = k;

cout<<"d's : "<<d<<endl;
cout<<"k's : "<<k<<endl;

delete d;

// cout<<"d's : "<<d<<endl;    //Undefined behavior, the pointer is invalid now
// cout<<"k's : "<<k<<endl;    //Undefined behavior, k is invalid as well

// delete k;    //Undefined behavior, k is invalid
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...