代码之家  ›  专栏  ›  技术社区  ›  Vizor Ahmad Mushtaq

std::make\u shared()、std::weak\u ptr和循环引用

  •  3
  • Vizor Ahmad Mushtaq  · 技术社区  · 7 年前

    我的问题是关于这一主张:

    如果任何std::weak\u ptr在所有共享所有者的生存期结束后引用由std::make\u shared创建的控制块,则T占用的内存将持续存在,直到所有弱所有者也被销毁,如果sizeof(T)较大,这可能是不需要的。 Source

    here ,该对象一直存在,直到最后一个弱ptr出现。

    例如:

    struct A
    {
        std::weak_ptr<A> parent;
    }
    
    void fn()
    {
        auto a=std::make_shared<A>();
        a->parent = a;
    } // Will it destroy here or not?
    
    3 回复  |  直到 6 年前
        1
  •  11
  •   ikh    7 年前

    它被摧毁了。这就是为什么 weak_ptr

    什么时候 a 摧毁 。这意味着对象的析构函数被调用,它将 a->parent

    不要混淆 具有 取消分配 shared_ptr 摧毁 .如果有 弱ptr 解除分配 -因为对象是用 std::make_shared .

        2
  •  3
  •   Jarod42    7 年前

    有点像

    std::weak_ptr<A> global;
    
    void foo()
    {
        auto a = std::make_shared<A>();
        global = a;
    }
    

    所以 global a . 在这里即使

        3
  •  0
  •   curiousguy    6 年前

    通过实现指针的对象可达性循环 也就是说,您可以遵循这些对象的私有实现中使用的指针,并返回到您开始的地方: a->parent std::shared_ptr 或由 std::make_shared .

    std::使共享 通过将元信息和托管对象放在一起,可以最大限度地减少动态内存分配的数量,但这与托管对象何时被破坏无关(这是唯一可以观察到的方面,因为没有特定于类的 operator new / operator delete 已使用)。因此,控制块是否与托管对象并置,或者是否有一个指向该对象的指针被单独分配,都无关紧要。

    在除少数退化情况外的所有情况下(其中智能指针由不释放任何内容的伪删除器构造),最后一个共享拥有智能指针的生命周期结束时会导致删除器运行,通常:

    • 表格的 delete p; p 是类型的参数 T* std::shared_ptr<U>
    • 或形式 p->~T() p 是由于 new (buff) T 在里面 std::make_shared<T>()

    p 可以从元信息中获得。

    从未从 U* 存储在任何特定位置的指针值 标准::shared\u ptr<U> 标准::shared\u ptr<U> 具有正确的静态类型:这就足够了 删除p; p 是传递给模板构造函数的类型的值),因为如果使用别名构造函数构造另一个构造函数,指针可能指向成员子对象或完全不同的完整对象 std::shared\u ptr 共享所有权。]

    因此,拥有指向控制块的指针通常允许恢复指向受控对象的指针,尽管无法通过公共接口获得指向完整对象的指针(除非指针传递给删除器,因此在C++中恢复指针的唯一方法是,如果指针丢失,则传递自定义删除器并等待调用)。当然可以通过在内存表示中导航来恢复指针(尽管该导航可能需要使用 dynamic_cast 对于编译时未知的类型,只要调试器知道所有派生类,就可以执行此操作)。

    a
    a->parent
       parent->control_block
               control_block.deleter (virtual call or stored function)
                             deleter.a
    

    如果指针存储在动态创建的删除器中,则需要创建 std::shared_ptr<U>(T*)

    a
    a->parent
       parent->control_block
               control_block.buffer
    

    对于使用单个分配创建的对象 make_shared :对象是在该缓冲区内构造的,因此 &control_block.buffer == a

    但指针的循环不是问题,只是所有权的循环,因为它意味着“生命控制的自我所有权”,即“只有当我的生命结束时,我才会毁灭自己”(也就是“当我进入析构函数时,我将进入析构师”),这是荒谬的。

    弱引用只拥有元信息,而不拥有信息 .