【问题标题】:Calling `.lock()` on weak_ptr returns NULL shared_ptr在weak_ptr 上调用`.lock()` 返回NULL shared_ptr
【发布时间】:2022-01-01 10:24:27
【问题描述】:

我对@9​​87654322@ 调用weak_ptr 的行为感到有些困惑。我的理解是.lock() 将返回一个相关类型的shared_ptr,如果它没有过期否则它将是一个空指针。

来自https://en.cppreference.com/w/cpp/memory/weak_ptr/lock

如果 std::weak_ptr::expired 返回 false,则共享拥有对象的所有权的 shared_ptr。

然而,这不是我看到的结果。下面的代码是Unit 类的一个方法,它应该将shared_ptr 返回给Unit 的父级:

unsigned Unit::getParentId() const {
    auto parent = parent_.lock();
    return parent->getId();
}

下面的调试器输出显示parent_ 作为weak_ptr 存在。但是,当我调用 auto parent = parent_.lock(); 时,它会返回一个 NULL 指针,如调试器输出的最后一行所示。

我显然在这里遗漏了一些非常基本的东西?

this = {const Unit *} 0x16f1af010 
 id_ = {unsigned int} 234
 name_ = {std::string} "Test"
 parent_ = {std::weak_ptr<Unit>} std::__1::weak_ptr<Unit>::element_type @ 0x00006000034d00d8 strong=0 weak=2
  __ptr_ = {std::weak_ptr<Unit>::element_type *} 0x6000034d00d8 
   id_ = {unsigned int} 0
   name_ = {std::string} "Root"
   parent_ = {std::weak_ptr<Unit>} nullptr
   children_ = {std::vector<std::shared_ptr<Unit>>} size=0
 children_ = {std::vector<std::shared_ptr<Unit>>} size=0
parent = {std::shared_ptr<Unit>} nullptr
 __ptr_ = {std::shared_ptr<Unit>::element_type *} NULL

【问题讨论】:

    标签: c++ c++14 weak-ptr


    【解决方案1】:

    弱指针只附加到现有的共享指针,弱指针本身不持有或创建任何对象指针。换句话说,如果你这样做:

    std::weak_ptr<int> wp;
    auto sp = wp.lock();
    

    那么它总是返回 nullptr。您必须在构造函数中或通过赋值(=)传递现有共享指针,例如

    std::shared_ptr<int> sp = std::make_shared<int>();
    std::weak_ptr<int> wp(sp);
    auto spl = wp.lock(); // now spl is not null
    

    或通过分配

    std::shared_ptr<int> sp = std::make_shared<int>();
    std::weak_ptr<int> wp;
    wp = sp;
    auto spl = wp.lock(); // now spl is not null
    

    只要共享指针的所有副本仍然存在,那么弱指针将在锁定时返回非空值。否则,如果不存在共享指针的副本,则弱指针将始终返回 null。

    在您的情况下,您没有任何共享指针的副本,因此在这种情况下,弱指针将始终在锁定时返回 null。

    【讨论】:

    • 谢谢@Arty,shared_ptr 必须在我假设的范围内。
    • @Paul 至少一个共享指针副本必须处于活动状态。这就是所需要的。如果您将共享指针分配(或通过构造函数传递)给弱指针,那么共享指针可能会超出范围,只要它不是唯一的副本。所以共享指针不需要在作用域内,你可能在某个地方有一个共享指针的堆副本。
    • 其实我以为我是用下面的方法做的。显然这是不正确的void Unit::setParent(shared_ptr&lt;Unit&gt; parent_ptr) { parent_ = parent_ptr; parent_.lock()-&gt;addChild(make_shared&lt;Unit&gt;(*this)); }
    • @Paul 我认为您的共享指针的最后一个副本在某处被破坏了。即使弱指针持有对共享指针的引用,仍然只有共享指针的副本很重要。如果最后一个共享指针被销毁,那么所有弱指针都将保持 NULL。
    • @Paul 所有指向同一个对象的共享指针形成了一种“集群”。弱指针只是对某些现有集群的引用。弱指针本身不管理任何指针。如果共享指针集群死亡(全部被破坏或超出范围),那么所有引用该集群的弱指针现在在锁定时将给出 NULL。要使弱指针在锁定时返回非空值,集群内的至少一个共享指针必须仍处于活动状态。如果在您的程序中所有共享指针都死了,那么您应该在任何地方使用共享指针而不是弱指针。共享ptr很轻,随处使用。
    猜你喜欢
    • 2017-10-02
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多