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_ptr
s 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.