Reputation: 876
So I'm having quite a hard time understanding why we have to use weak_ptr
especially with cyclic reference problems, consider this code:
class B; //forward declaration
class A {
shared_ptr<B> b_ptr;
public:
void set_B(shared_ptr<B>& b)
{
b_ptr = b;
}
A() { cout << "A constructor" << endl; }
~A() { cout << "A destructor" << endl; }
};
class B {
shared_ptr<A> a_ptr;
public:
void set_A(shared_ptr<A>& a)
{
a_ptr = a;
}
B() { cout << "B constructor" << endl; }
~B() { cout << "B destructor" << endl; }
};
int main() {
shared_ptr<A> a = make_shared<A>();
shared_ptr<B> b = make_shared<B>();
a->set_B(b);
b->set_A(a);
}
Now from what I heard, when both a
and b
go out of scope and their reference count is 0 they try to deallocate and destroy the pointed to memory, but in this case they can't do it because both pointed to objects have shared_ptr
's that have an reference count of 1 which makes them undeletable, now is that true?
Then, it says to fix this problem I have to make the shared_ptr
in class B
a weak_ptr
, now why is that? it still has an reference count of 1, doesn't it? And even with the weak_ptr there is still the shared_ptr<B> b_ptr;
which remains with a reference count of 1, so how can it be deleted?
Also it mentions that a weak_ptr
breaks strong ownership reference but how can a weak_ptr have no ownership, how will it access the object?
Thanks in advance.
Upvotes: 2
Views: 181
Reputation: 217283
With all std::shared_ptr
, you have:
int main() {
std::shared_ptr<A> a = std::make_shared<A>(); // ref_count_a = 1
std::shared_ptr<B> b = std::make_shared<B>(); // ref_count_b = 1
a->set_B(b); // ref_count_b = 2
b->set_A(a); // ref_count_a = 2
} // ref_count_a = 1 && ref_count_b = 1
// memleak due to the cycle
With
class B {
std::weak_ptr<A> a_ptr;
// ...
};
it becomes:
int main() {
std::shared_ptr<A> a = std::make_shared<A>(); // ref_count_a = 1
std::shared_ptr<B> b = std::make_shared<B>(); // ref_count_b = 1
a->set_B(b); // ref_count_b = 2
b->set_A(a); // ref_count_a = 1 , weak_ref_a = 1
} // ref_count_a = 0 && ref_count_b = 1
// -> release a -> ref_count_b = 0
// -> release b (+ control block) -> weak_ref_a = 0
// -> release control block of a
Also it mentions that a weak_ptr breaks strong ownership reference but how can a weak_ptr have no ownership, how will it access the object?
The control maintains a counter for the shared_ptr
(to release the object)
and a counter for weak_ptr
to release the control block.
weak_ptr retrieves the shared_ptr thanks to control block.
Finally I heard that a weak_ptr is a smart pointer which can use methods such as lock() or expired() to manage a shared_ptr, again is this correct?
Yes
Upvotes: 3