Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there no operator< for class std::weak_ptr? [duplicate]

I'm using weak pointers as keys in a map. However, when I tried to compile, I got ugly messages which I interpreted to mean that I lacked a comparison operator for the std::weak_ptr, which, obviously, is required in a std::map, as it orders its elements according to key value.

Now, however, the weak_ptr class is a smart-pointer type class, and, as such, works with pointers to some managed data.

Is there a good reason why this class would NOT provide a base implementation of the operator< method ? I mean, comparing the pointer values seem pretty obvious to me, and, if it is required that it works in a different way, then one should be able to extend, or redefine, the method, to get the expected behavior instead, wouldn't it ?

Your insight would be much appreciated, here. Thanks in anticipation.

like image 271
Kzwix Avatar asked Apr 09 '18 12:04

Kzwix


People also ask

What is the use of Weak_ptr in C++?

By using a weak_ptr , you can create a shared_ptr that joins to an existing set of related instances, but only if the underlying memory resource is still valid. A weak_ptr itself does not participate in the reference counting, and therefore, it cannot prevent the reference count from going to zero.

What is std :: Weak_ptr?

std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.

How is Weak_ptr implemented?

To implement weak_ptr , the "counter" object stores two different counters: The "use count" is the number of shared_ptr instances pointing to the object. The "weak count" is the number of weak_ptr instances pointing to the object, plus one if the "use count" is still > 0.

Is std :: Weak_ptr thread safe?

Note that the control block used by std::weak_ptr and std::shared_ptr is thread-safe: different non-atomic std::weak_ptr objects can be accessed using mutable operations, such as operator= or reset , simultaneously by multiple threads, even when these instances are copies or otherwise share the same control block ...


2 Answers

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();
}
like image 139
Richard Hodges Avatar answered Nov 03 '22 01:11

Richard Hodges


UPDATE: There is a well-defined way to compare std::weak_ptr, see @Richard's answer. I will leave my answer for historical archival purposes.


Implementing a good operator< would require creating a shared_ptr from the weak_ptr and calling its operator<. This is

  1. a "costly" operation
  2. undefined when the underlying shared_ptr does not exist anymore.

It would be difficult to get a well-defined and performant ordering of weak_ptrs in general.

Note that you can always pass a custom comparator to your map object, which you can implement any way you want and keep local to only that object. But then it's up to you to figure out a good way to do this. Perhaps you could use the pointer to the control block to the connected shared_ptr, but that is an implementation detail you cannot access. So I really see no meaningful way of doing this.

like image 21
rubenvb Avatar answered Nov 03 '22 02:11

rubenvb