Equality-compare std::weak_ptr
Completely rewriting this answer because I totally misunderstood. This is a tricky thing to get right!
The usual implementation of std::weak_ptr
and std::shared_ptr
that is consistent with the standard is to have two heap objects: the managed object, and a control block. Each shared pointer that refers to the same object contains a pointer to the object and to the control block, and each weak pointer likewise. The control block keeps a record of the number of shared pointers and the number of weak pointers, and deallocates the managed object when the number of shared pointers reaches 0; the control block itself is deallocated when the number of weak pointers also reaches 0.
This is complicated by the fact that the object pointer in a shared or weak pointer can point to a subobject of the actual managed object, e.g. a base class, a member, or even another heap object that is owned by the managed object.
S0 ----------______ MO <------+
\__ `----> BC |
\_ _______--------> m1 |
___X__ m2 --> H |
S1 -/ \__ __----------------^ |
\___ _____X__ |
____X________\__ |
W0 /----------------`---> CB -------+
s = 2
w = 1
Here we have two shared pointers pointing respectively to a base class of the managed object and to a member, and a weak pointer pointing to a heap object owned by the managed object; the control block records that two shared pointers and one weak pointer exist. The control block also has a pointer to the managed object, which it uses to delete the managed object when it expires.
The owner_before
/ owner_less
semantics are to compare shared and weak pointers by the address of their control block, which is guaranteed not to change unless the pointer itself is modified; even if a weak pointer expires because all shared pointers have been destructed, its control block still exists until all weak pointers have also been destructed.
So your equals
code is absolutely correct and thread safe.
The issue is that it's not consistent with shared_ptr::operator==
because that compares the object pointers, and two shared pointers with the same control block can point to different objects (as above).
For consistency with shared_ptr::operator==
, writing t.lock() == u
will be absolutely fine; note however that if it returns true
then it's still not definite that the weak pointer is a weak pointer of the other shared pointer; it could be an alias pointer and so could still expire in following code.
However, comparing control blocks has less overhead (because it doesn't need to look at the control block) and will give the same results as ==
if you're not using alias pointers.
I think that there's something of a deficiency in the standard here; adding an owner_equals
and owner_hash
would allow using weak_ptr
in unordered containers, and given owner_equals
it actually becomes sensible to compare weak pointers for equality, as you can safely compare the control block pointer then the object pointer, since if two weak pointers have the same control block then you know that either both or neither are expired. Something for the next version of the standard, perhaps.
Missing equality between shared_ptr and weak_ptr
weak_ptr
doesn' have a get()
method because you need to explicitly lock the weak_ptr
before you can access the underlying pointer. Making this explicit is a deliberate design decision. If the conversion were implicit it would be very easy to write code that would be unsafe if the last shared_ptr
to the object were to be destroyed while the underlying pointer obtained from the weak_ptr
was still being examined.
This boost page has a good description of the pitfalls and why weak_ptr
has such a limited interface.
If you need to do a quick comparison, then you can do shared == weak.lock()
. If the comparison is true then you know that weak
must still be valid as you hold a separate shared_ptr
to the same object. There is no such guarantee if the comparison returns false.
Comparing two sets of std::weak_ptr
Since weak_ptr doesn't support '==', but in this case you can use the comparison operator of the set try:
bool result = !(std::lexicographical_compare(set1.begin(), set1.end(),
set2.begin(), set2.end(),
set1.value_comp()) ||
std::lexicographical_compare(set2.begin(), set2.end(),
set1.begin(), set1.end(),
set1.value_comp()));
This will test for equivalence, not equality. And it lacks a certain... clarity.
Why is there no operator for class std::weak_ptr?
std::owner_less
is the correct way to order smart pointers as keys in maps.
#include <map>
#include <memory>
#include <string>
struct Foo
{
};
using my_key = std::weak_ptr<Foo>;
using my_comp = std::owner_less<my_key>;
int main()
{
auto m = std::map<my_key, std::string, my_comp>();
auto p = std::make_shared<Foo>();
auto p1 = std::make_shared<Foo>();
m.emplace(p, "foo");
m.emplace(p1, "bar");
p.reset();
p1.reset();
}
Comparator operator in weak_ptr C++
If you want to compare strings stored in weak_ptr do this:
bool operator<(StubClass d, StubClass c)
{
std::shared_ptr<std::string> a = d.b.lock();
std::shared_ptr<std::string> b = c.b.lock();
if (!a && !b)
return false;
if (!a)
return true;
if (!b)
return false;
return *a < *b;
}
Run result
How to use assert to check whether a weak_ptr is nullptr
If you want to check whether the referenced model has already been deleted or whether the weak reference is empty -> use std::weak_ptr::expired().
reference documentation: https://en.cppreference.com/w/cpp/memory/weak_ptr/expired
Related Topics
Programmatically Check Whether My MAChine Has Internet Access or Not
Access to Method Pointer to Protected Method
Getting Input from User Using Cin
Why Is the Data Type Needed in Pointer Declarations
Displacement Map Filter in Opencv
Calling Constructors in C++ Without New
Why Use an Initialization Method Instead of a Constructor
C++ Get Handle of Open Sockets of a Program
What's the Deal with Boost.Asio and File I/O
Why Does (1 << 31) >> 31 Result in -1
Std::Filesystem' Has Not Been Declared After Including <Experimental/Filesystem>
How to Simulate Printf's %P Format When Using Std::Cout
Questions Regarding C++ Non-Pod Unions
What Are the Stages of Compilation of a C++ Program