#c #pointers #memory-management #delete-operator
#c #указатели #управление памятью #оператор удаления
Вопрос:
Меня немного смущает следующий код
int main()
{
int* a = new int{12};
int* b = new int;
b = a;
delete a;
delete b;
return 0;
}
Код возвращает ошибку, которая
a.out(27538,0x10ade7e00) malloc: *** error for object 0x7f8c18504160: pointer being freed was not allocated
a.out(27538,0x10ade7e00) malloc: *** set a breakpoint in malloc_error_break to debug
zsh: abort ./a.out
Мой вопрос в том, что, когда я удаляю a, автоматически ли он удаляет b? Каков здесь механизм, я немного теряюсь.
Комментарии:
1. Вы дважды удаляете один указатель и пропускаете другой.
2. Оба
a
иb
указывают на одну и ту же память. Удаление обоих приводит к удалению одного и того же блока памяти 2 раза, что является неопределенным поведением. Вы также пропустили память, на которуюb
первоначально указывали. Это невозможно удалить, потому что адрес был удален приb = a;
назначении.3. Вы совершаете ошибку, глядя на имя переменной вместо того, чтобы смотреть на значение переменной. Если вы отладили код, вы увидите, что после этих вызовов
new
обаa
иb
имеют разные значения. Важны именно эти значения, а не имя. Когда вы выполнилиdelete
вызов, вы дважды удаляете одно и то же значение, поскольку вы присвоили значениеa
tob
.
Ответ №1:
b = a; // here the int that b pointed at "leaks" (you have no way of deleting it)
delete a; // here "a" is deleted first
delete b; // here "a" is deleted a second time (undefined behavior)
Когда вы присваиваете значение a
to b
, значение (адрес, если хотите) b
, ранее содержащееся, забывается. Оба a
и b
затем указывают на один и тот же объект. Затем вы потеряли все возможности для delete
исходного объекта b
, на который указывали. Когда вы тогда delete b
, вы на самом деле пытаетесь удалить a
второй раз.
Комментарии:
1. Я бы сказал, что
b = a;
это строка, в которой «b» протекает.2. @eerorika Я могу это купить. Я выбираю «потерянный», но, вероятно, правильнее сказать «утечка» прямо там.
Ответ №2:
Давайте пройдемся по коду построчно.
int* a = new int{12};
Это создает новую переменную, вызываемую a
типом int*
, и инициализирует ее, указывая на вновь выделенное целое число, которому присвоено значение 12.
int* b = new int;
Это создает новую переменную, вызываемую b
типом int*
, и инициализирует ее, указывая на вновь выделенное целое число.
b = a;
Это изменяет b
значение, на которое указывает a
. Значение, возвращенное во втором вызове new
, теперь потеряно, и эта память утекает, поскольку передать ее больше невозможно delete
.
delete a;
При этом удаляется объект a
, на который указывает объект, выделенный первым.
delete b;
Упс, это попытка удалить объект b
, на который указывает, но b
не указывает ни на один существующий в данный момент объект. Тот, который был выделен первым, был просто удален, и никакого указателя на второй не существует. Так что это ошибка.
Я подозреваю , что вы думаете , что delete a;
это удаляет a
. Это не так. Он удаляет любой объект a
, на который указывает , и требует , чтобы a
он был указателем и указывал на действительный объект , который был выделен new
.
Ответ №3:
При удалении указателя Все указатели, ссылки, итераторы и т. Д., указывающие на уничтоженный объект, Становятся недействительными. Из-за назначения b = a
b указывает на тот же объект, что и a, поэтому, когда a удаляется, b становится недействительным. Удаление недопустимого указателя имеет неопределенное поведение.
Обратите внимание, что это b = a
делает невозможным удаление выделения, на которое ранее указывал b. Это называется утечкой памяти.