@ZSashka

Какое время жизни объекта в std::unique_ptr?

Добрый день. Имею следующий код:
#include <log.h>

#include <memory>

struct ttt
{
    ttt() {}
    ~ttt() { LDEBUG("Removing"); }
    void foo() { LSDEBUG("I am alive", this); }
};

int main(int argc, char *argv[])
{
    ttt *t = new ttt();

    {
        const std::unique_ptr<ttt> up(t);
        up->foo();
    }

    t->foo();

    return 0;
}


На выходе имею следующее:
[Tue Dec 19 00:07:03 2017][DEBUG] I am alive 0x55d00a5a96c0
[Tue Dec 19 00:07:03 2017][DEBUG] Removing
[Tue Dec 19 00:07:03 2017][DEBUG] I am alive 0x55d00a5a96c0

Как так получается что объект все еще жив? Ведь по идее unique_ptr должен его удалить. Собирал с GCC 7.2.1.
  • Вопрос задан
  • 197 просмотров
Решения вопроса 1
terrier
@terrier
Хотите еще более клевую штуку покажу?
int main(int argc, char *argv[])
{
    ttt *t = new ttt();
    t->foo();
    delete t;

    t->foo();

    return 0;
}

Выводит
Alive 0x55d7770d0c20
Removing
Alive 0x55d7770d0c20
( собирал чем попало ).
При вызове деструктора для объекта никто не обязан как-то его "разрушать", скажем занулять область памяти, где он лежал. Это просто договоренность с программистом, что объект удален и обращаться к нему не надо. Что будет если обратиться? Undefined behaviour, частный случай которого мы с вами и наблюдаем.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@Mercury13
Программист на «си с крестами» и не только
Уничтоженный unique_ptr уничтожит ваш объект.

«Уничтожит» — это значит, вызовет деструктор и сделает память доступной менеджеру памяти. Теперь другие указатели, которые смотрят на этот объект, будут «висячими», и при их разыменовании программа может сделать ЧТО УГОДНО.

А теперь посмотрим, что именно ей угодно. Ваша функция foo() невиртуальная и не имеет дела с полями, ей нужен только this (указатель на объект), который даже не разыменовывается. Она в принципе не может вылететь, даже если десять раз занулить этот объект!

То, что вы хотите сделать — это семантика std::shared_ptr/weak_ptr.
std::shared_ptr<ttt> sh1 = std::make_shared<ttt>();
std::weak_ptr<ttt> we = sh1;
{
  std::shared_ptr<ttt> sh2 = sh1;
  sh1 = nullptr;
}
std::cout << we.expired();  // должно быть true


UPD. Вот для таких, как ты, и ввели в C++14 функцию std::make_unique, по аналогии с std::make_shared. Просто чтобы было меньше таких ошибок.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы