I'm new to smart pointers and I'm trying to wrap around my head why a weak_ptr would expire after a dereference operator. The code I used to test is here:
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
struct node
{
weak_ptr<node> parent;
shared_ptr<node> child;
int val;
};
shared_ptr<node> foo()
{
shared_ptr<node> a = make_shared<node>();
shared_ptr<node> b = make_shared<node>();
a->val = 30;
b->val = 20;
b->parent = a;
a->child = b;
return a;
}
int main()
{
shared_ptr<node> c = foo();
node d = *foo();
if (c->child->parent.expired())
{
cout << "weak ptr in c has expired." << endl;
}
if (d.child->parent.expired())
{
cout << "weak ptr in d has expired." << endl;
}
return 0;
}
The program outputs weak ptr in d has expired.
I don't understand why when d
uses the dereference operator, it expires. In regards to this, is there anyway to prevent it (other than not dereferencing it)?
I tried as mrtnj suggested by changing the weak_ptr
in node to shared_ptr
but I think I have a memory leak. I changed the node
class to
struct node
{
shared_ptr<node> parent;
shared_ptr<node> child;
int val;
};
and then modified the source code to add a tryCreate
function.
void tryCreate()
{
node d = *foo();
}
and then called it in my main
such that my main looks like
int main()
{
tryCreate();
return 0;
}
I used Visual Studio 2015's memory profiling and noticed that there were only allocations and no deallocations. I changed parent
into a weak_ptr
and I see deallocations. Am I doing something wrong or is it indeed a requirement to use weak_ptr
in these cyclic condition?
A weak_ptr
expires when the last shared_ptr
that refers to the object, is destroyed.
In your code that happens in the statement
node d = *foo();
Here foo()
returns a shared_ptr
, which is the last shared_ptr
that refers to that object (the parent object of the two created by foo
). And this shared_ptr
is a temporary that's destroyed right there, after the derefencing. That reduces the reference count to 0 and the weak_ptr
expires.
Since the shared_ptr
was the last one, the object is destroyed, which causes its child object to also be destroyed. Thus the later code that delves into these objects has undefined behavior.
Since d
contains a shared_ptr
to the child node, the child node is not destroyed at this point, as noted by Miles Budnek in a comment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With