Home > other >  Why make_shared call the destructor even if there are still weak pointer?
Why make_shared call the destructor even if there are still weak pointer?

Time:01-27

From theory, one difference between make_shared() and shared_ptr is the memory allocation technique. make_shared() should use a single block, while shared_ptr should use two blocks.

One make_shared() drawback should be that memory can't be freed if there is even a single weak_ptr alive.

Can someone explain why the output of this program is always the same independently from the function I use to create the 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;
}

I was expecting the destructor method to be called at the end, since the weak_ptr is still alive, why is that not happening?

CodePudding user response:

Even if its memory can't be freed, the object held by a shared_ptr will still be destroyed when the (non-weak) refcount reaches zero. Object destruction and memory release are two separate operations that don't need to happen at the same time.

In general, since the "one allocation" behavior of make_shared is an optimization, it should not have an observable effect on your code.

CodePudding user response:

Simply making a std::weak_ptr refer to a std::shared_ptr does not increase the reference count of the object that the shared_ptr manages. The std::weak_ptr is just a passive observer until it is locked, returning a new shared_ptr which either 1) refers to the shared object incrementing its reference count if it has not expired yet, or else 2) contains nullptr if the object has expired.

When a shared object's reference count falls to 0 (ie, no more std::shared_ptrs refer to it), the object is destroyed immediately. In your example, that happens on the call to sp.reset(), not when main() exits. You created 3 shared_ptr references to an mc object, and then you reset() those 3 references, thus destroying the object before your for loop then printed out the reference count.

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

If what you were expecting were actually true, that a std::weak increases a shared object's reference count, that would defeat the whole purpose of std::weak_ptr, making it act just like std::shared_ptr. std::weak_ptr is a "weak" (passive, no active reference) smart pointer, whereas std::shared_ptr is a "strong" (active reference) smart pointer.

  • Related