Как это работает? Назначение указателя указателю

#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? Может кто-нибудь объяснить? Спасибо за помощь

Вы можете найти этот вопрос полезным для понимания того, что такое указатели. Этот сценарий рассматривается под заголовком «утечка памяти».

Brian61354270 10.12.2020 21:53

Важный момент: указатель — это переменная, которая содержит адрес и может использоваться для доступа к объекту по этому адресу. В остальном это точно так же, как и любая другая переменная, поэтому p2 = p1; заменяет адрес, сохраненный p2, на адрес, сохраненный p1.

user4581301 10.12.2020 21:54

@ Брайан: Спасибо за ссылку. Это объяснение является очень хорошей аналогией управления памятью. Это было полезно

Niranjan reddy Suravarapu 10.12.2020 22:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

На что сейчас ссылается указатель p2?

Ничего. Он болтается. Он указывал на то же самое, на что указывал p1, но вы удалили это.

Следовательно, ваш *p2 сломан, как и ваш delete p2; они оба имеют неопределенное поведение.

Вы также слили второй new int, потому что p2 раньше указывал на него, но перестал делать это, когда вы написали p2 = p1 (вместо этого вы изменили его, чтобы он указывал на первый new int, как это делает p1), и нет другого способа сослаться на него. .

Хорошая диаграмма. Я бы предложил также включить последнее cout << *p2 заявление в огонь

Remy Lebeau 10.12.2020 22:15

@RemyLebeau Хорошая идея

Asteroids With Wings 10.12.2020 22:25

@Астероиды с крыльями, боже мой! это было замечательно. По-видимому, мой код имеет два греха: утечка памяти, попытка удалить висячий объект. Мне понравилась огненная часть

Niranjan reddy Suravarapu 10.12.2020 22:35
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». Теперь я понимаю, что произошло.

Niranjan reddy Suravarapu 10.12.2020 22:43

Другие вопросы по теме