Почему выделенный в куче объект все еще может быть использован после вызова деструктора? - PullRequest
2 голосов
/ 07 июня 2019

Я делаю эксперименты по самообучению с C ++ 11 shared_pointers, чтобы понять, как они получают владение необработанным указателем. Если они вступают во владение объектом, на который указывает необработанный указатель, тогда необработанный указатель также должен указывать на nullptr при удалении объекта.

Я пробовал пример кода

#include<iostream>
#include<memory>
class X
{
    public:
        X(){std::cout<<"X created\n";}
        virtual ~X(){std::cout<<"X destroyed\n";}
        void show(){std::cout<<"show()\n";}
};

int main()
{
    X *xp = new X;
    {
        std::shared_ptr<X> xs1(xp);
    }

    if(xp)
        xp->show();
    return 0;
}

Вывод выглядит так после g ++ -std = c ++ 14

X created
X destroyed
show()

xp должно быть nullptr, но все же xp->show() работает. Почему?

Ответы [ 5 ]

2 голосов
/ 07 июня 2019

Это C ++, если вы не назначите nullptr, оно всегда будет сохранять значение.shared_ptr берет копию значения указателя и вызывает delete при уничтожении shared_ptr.Это не подразумевает каких-либо изменений в исходном необработанном указателе, который вы использовали для инициализации shared_ptr.

. Также, пока не используется ни один элемент, вызов show, вероятно, всегда будет работать, потому что не выполняется чтение в освобожденное хранилище.попытка.Как правильно отмечено, это неопределенное поведение.

0 голосов
/ 07 июня 2019

xp должно быть nullptr

Нет, вы не изменили значение xp. Вы уничтожили объект, на который он указал. delete не охотится за памятью, ищет значения, равные тому, что ей передано, для изменения.

Указатель не является объектом, на который он указывает. Это отдельный объект со своей собственной жизнью. Программист должен убедиться, что вы не разыменовываете указатели с недопустимыми значениями.

0 голосов
/ 07 июня 2019

Если какая-то функция внутри класса C ++ не имеет доступа ни к одному из своих членов, как в этом случае для функции show (), то даже после того, как объект уничтожен, если вызывается такая функция, то она работает!!!Даже если вы сделаете указатель равным nullptr !!!

Это не удивительно, потому что мы можем думать, что компилятор C ++ генерирует простые функции, подобные C, для функций класса, и добавляет объект самого класса в качестве аргументатакая функция.Пока к указателю нет доступа, проблем не будет.

Однако, в целом, полагаться на такое поведение не рекомендуется.

Кроме того, не рекомендуется сначала создавать объект в куче, а затем добавлять его в shared_ptr.Вместо этого создайте анонимный объект непосредственно следующим образом:

std :: shared_ptr xs1 (new X);

И никогда не имейте никакого другого дескриптора для указателя объекта, на который указывает shared_ptr, потому что, shared_ptr должен управлять жизненным циклом.

0 голосов
/ 07 июня 2019

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

0 голосов
/ 07 июня 2019

Другой способ доказать это - использовать значение и не указывать на тот же объект, изменив значение в деструкторе.

#include<iostream>
#include<memory>
class X
{
    public:
        int a =4;
        X(){std::cout<<"X created\n";}
        virtual ~X(){std::cout<<"X destroyed\n"; a=5;}
        void show(){std::cout<<"show() "<<a<<"\n";}
};

int main()
{
    X *xp = new X;
    {
        std::shared_ptr<X> xs1(xp);
        xs1->show();
    }

    if(xp)
        xp->show();

    return 0;
}

Вывод похож на

X created
show() 4
X destroyed
Before calling show
show() 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...