c++ std::weak_ptr 堆叠对象

c++ std::weak_ptr to stack object

我需要一个指向可能超出范围的堆栈对象的指针。有人告诉我弱指针可以实现这一点,但以下代码会引发段错误:

#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;
}

这是为什么?

编辑

我找到了一个似乎有效的解决方案。

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);

问题出在这两行代码:

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

这里你创建一个 std::shared_ptr,从中初始化 wp 并立即销毁 std::shared_ptr。在 assert 点,wp 已经过期并且 lock() returns 为空 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
}