c++ 为什么make_shared调用析构函数,即使仍然存在弱指针?

5ssjco0h  于 2023-01-28  发布在  其他
关注(0)|答案(2)|浏览(246)

从理论上讲,make_shared()shared_ptr之间的一个区别是内存分配技术。make_shared()应该使用单个块,而shared_ptr应该使用两个块。
make_shared()的一个缺点是,即使只有一个weak_ptr活动,也无法释放内存。
有人能解释一下为什么这个程序的输出总是相同的,而与我用来创建shared_ptr的函数无关吗?

#include <iostream>
#include <memory>

class mc
{
    public:
      mc(int p):p_{p} {std::cerr<<"Constructor"<<std::endl;}
      ~mc() { std::cerr<<"Destructor"<<std::endl;}    
    private:
      int p_;    
};

std::weak_ptr<mc> wp3;

int main()
{
 
    auto sp=std::make_shared<mc>(4);
    auto sp2=sp;
    auto sp3{sp};
    wp3=std::weak_ptr<mc>{sp};
    
    sp2.reset();
    sp3.reset();
    sp.reset();
     
    for (int i =0;i< 5;i++) {std::cerr<<sp.use_count()<<std::endl;}   

    return 0;
}

我希望在最后调用析构函数方法,既然weak_ptr仍然存在,为什么没有发生呢?

7kjnsjlb

7kjnsjlb1#

即使shared_ptr的内存不能被释放,当(非弱)refcount达到零时,它所持有的对象仍然会被销毁。对象销毁和内存释放是两个独立的操作,不需要同时发生。
一般来说,由于make_shared的“一次分配”行为是一种优化,因此它不会对代码产生明显的影响。

vybvopom

vybvopom2#

简单地使std::weak_ptr引用std::shared_ptr并不增加shared_ptr管理的对象的引用计数。std::weak_ptr只是一个被动的观察者,直到它被锁定,返回一个新的shared_ptr,该新的shared_ptr要么1)引用共享对象,如果它还没有过期,则递增其引用计数,或者2)如果对象已经过期,则包含nullptr
当共享对象的引用计数福尔斯0时(即不再有std::shared_ptr引用它),对象立即被销毁。在您的示例中,这发生在调用sp.reset()时,而不是main()退出时。您创建了3个shared_ptr引用mc对象,然后您reset()这3个引用,从而在for循环打印出引用计数之前销毁对象。

int main()
{
 
    auto sp=std::make_shared<mc>(4); // object created, refcnt is 1
    auto sp2=sp;  // refcnt becomes 2
    auto sp3{sp}; // refcnt becomes 3
    wp3=std::weak_ptr<mc>{sp}; // refcnt stays 3 !!
    
    sp2.reset(); // refcnt becomes 2
    sp3.reset(); // refcnt becomes 1
    sp.reset();  // refcnt becomes 0, object destroyed, wp3 is now expired !!
     
    for (int i =0;i< 5;i++) {std::cerr<<sp.use_count()<<std::endl;} // refcnt is 0

    return 0;
} // sp, sp2, sp3 are destroyed

如果std::weak增加了共享对象的引用计数,那么std::weak_ptr的作用就完全失效了,它的行为就像std::shared_ptr一样。std::weak_ptr是一个“弱”(被动的,没有主动引用)智能指针,而std::shared_ptr是一个“强”(主动引用)智能指针。

相关问题