Weak reference
12345678910111213141516171819202122232425262728293031323334 | #include <memory>
class bar;
class foo
{
public:
foo(const std::shared_ptr<bar>& b)
: forward_reference{b}
{ }
private:
std::shared_ptr<bar> forward_reference;
};
class bar
{
public:
void set_back_reference(const std::weak_ptr<foo>& f)
{
this->back_reference = f;
}
void do_something()
{
std::shared_ptr<foo> shared_back_reference = this->back_reference.lock();
if (shared_back_reference) {
// Use *shared_back_reference
}
}
private:
std::weak_ptr<foo> back_reference;
}; |
This pattern is licensed under the CC0 Public Domain Dedication.
Intent
Maintain a non-owning reference to a shared dynamically allocated object to break circular dependencies.
Description
The std::weak_ptr
type represents
a non-owning reference to dynamically allocated object with
shared ownership (std::shared_ptr
). As
they do not contribute to the reference count of the managed object
they refer to, the object can be destroyed at any time when all
std::shared_ptr
s give up ownership. However, a
std::weak_ptr
can be converted to a std::shared_ptr
to provide
temporary ownership and safe access to the object.
In the example code, we have two classes: foo
on lines 5–14, and bar
on
lines 16–30. A foo
object has shared ownership of a bar
(line 13), and
bar
requires some form of reference back to the foo
that owns it.
If this back reference were a std::shared_ptr<foo>
, it would introduce
a circular dependency, making it impossible for either object to be
destroyed. If it were a normal reference type (foo&
), it risks
refering to a deleted object when it attempts to use it, as the
lifetime of foo
is independent of bar
.
The solution is to use a std::weak_ptr<foo>
, as on line 33. When
bar
needs to use foo
, it checks if bar still exists by calling
lock
on the std::weak_ptr
to take temporary shared ownership
(line 26). If the returned std::shared_ptr
is not empty, bar
can
safely use it to access the foo
object (lines 27–29).