c ++ std :: weak_ptr для стекового объекта - PullRequest
0 голосов
/ 13 февраля 2020

Мне нужен указатель на объект стека, который может go выйти из области видимости. Мне сказали, что слабый указатель может достичь этого, но следующий код выдает ошибку сегмента:

#include <memory>
#include <cassert>
int main()
{

    std::weak_ptr<int> wp;

    {
        auto a = 4;

        wp = std::shared_ptr<int>(&a, [](auto){});
        assert(*wp.lock().get() == 4);
    }

    assert(wp.lock().get() == nullptr);

    return 0;
}

Почему это так?

edit

Я нашел решение, которое, кажется, работает.

std::weak_ptr<int> wp;

{
    auto a = 4;

    auto sp = std::shared_ptr<int>(&a, [](auto){});
    wp = sp;
    assert(*wp.lock().get() == 4);
}

assert(wp.lock().get() == nullptr);

Но комментатор сказал мне, что это неопределенное поведение. Почему это работает, и почему это UB?

edit2

Другой комментатор сказал, что это потому, что общий указатель остается в области видимости, но если это случай, почему это все еще работает?

std::weak_ptr<int> wp;

{
    auto a = 4;
    auto sp = std::shared_ptr<int>();

    {
        sp = std::shared_ptr<int>(&a, [](auto){});
        wp = sp;
        assert(*wp.lock().get() == 4);
    } //shared pointer out of scope

    assert(*wp.lock().get() == 4);

} // stack object out of scope

assert(wp.lock().get() == nullptr);

1 Ответ

2 голосов
/ 13 февраля 2020

Проблема в этих двух строках кода:

wp = std::shared_ptr<int>(&a, [](auto){});
assert(*wp.lock().get() == 4);

Здесь вы создаете std::shared_ptr, инициализируете wp из него и немедленно уничтожаете std::shared_ptr. В точке assert wp уже истек срок действия, а lock() возвращает ноль std::shared_ptr. Разыменование нулевого указателя приводит к неопределенному поведению.

Помимо вышеизложенного, общий подход является работоспособным:

{
    auto a = 4;

    auto sp = std::shared_ptr<int>(&a, [](auto){}); // create a shared_ptr and keep it
    wp = sp; // initialize weak_ptr from it
    assert(*wp.lock().get() == 4); // sp is still alive, so wp.lock().get() != nullptr
}
...