4

If I have a vector<weak_ptr<Type>>, I cannot use vector::erase(remove()) to remove the required weak_ptr, because it does not have a comparison operator==.

A lambda predicate has to be passed to remove_if in vector::erase(remove_if())comparing the underlying raw pointers accessed via weak_ptr::_Get()

The _Get() begins with an underscore and a capital letter meaning that it's reserved for the implementation and isn't meant to be accessed by the user.

It's clear that weak_ptrs were not meant to be stored this way, but why?


I was thinking of using a vector<weak_ptr<>> to hold weak_ptrs in a child class of only some of the objects I have in the manager class that need further processing and thus assure, by lock()ing, that they have not been deleted in the managing class (in a multithreaded application).

The manager alerts the child class of object creation and deletion, keeping the vector<weak_ptr<>> up-to-date.

Deadfish
  • 64
  • 5
  • 1
    What would you expect `==` to compare? The same `weak_ptr`? Or different `weak_ptr`s to the same object? Or different `weak_ptr`s to different objects with the same value? – Galik Apr 13 '18 at 00:59
  • Related: https://stackoverflow.com/questions/12301916/equality-compare-stdweak-ptr and it contains a link to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1590.html – Barmar Apr 13 '18 at 00:59
  • Possible duplicate of [Equality-compare std::weak\_ptr](https://stackoverflow.com/questions/12301916/equality-compare-stdweak-ptr) – Joseph D. Apr 13 '18 at 01:00
  • Also can you explain further the code using `std::remove_if` that failed to work? – Galik Apr 13 '18 at 01:05
  • 2
    Your predicate could do `a.lock() == b.lock()`, and not rely on internal implementation details. – Igor Tandetnik Apr 13 '18 at 01:14
  • @IgorTandetnik but that would say that any expired pointers are the same, which is perhaps not the historic truth. In many cases it might be acceptable, but if you were trying to remove all handlers for a particular expired object, you would remove too much. – Gem Taylor Apr 13 '18 at 10:28
  • I thought you might be able to take a hash from the weak ptr, but that does not appear to be supported. You could take the hash of the smart pointer when you inserted the weak pointer but that seems like extra work. – Gem Taylor Apr 13 '18 at 10:31
  • 1
    @GemTaylor All expired handles *are* the same. There's no (standard, portable) way of telling them apart; they don't keep track of their provenance. If you think you need that, then you need to keep some form of it alongside the `weak_ptr` instance. – Igor Tandetnik Apr 13 '18 at 12:09
  • @IgorTandetnik Yes, that is clearly the published interface. Internally, of course, they are distinct if they stub to different actual objects, even if the objects have expired. I admit that I find it hard to think of a real case where I would care. – Gem Taylor Apr 13 '18 at 16:55
  • I guess the only other issue is that there is work involved in locking a "good" weakptr. If I was scanning through a list of weakptr to find a match this cost might be significant, compared to a simple value compare. And I can't store them in any sort of hash or set based on their "current" lock value, as the lock value decays to null – Gem Taylor Apr 13 '18 at 16:57
  • Some implementations may not even remember the "address" of the object that is now destroyed, with the memory already freed. And you can't even do anything with such pointer in C/C++. – curiousguy Apr 27 '18 at 04:59

1 Answers1

0

You can use the erase-remove idiom with an explicit predicate.

For example:

#include <functional>
#include <iostream>
#include <memory>
#include <vector>

using std::cout;
using std::make_shared;
using std::remove_if;
using std::vector;
using std::weak_ptr;

int main()
{
  auto p7 = make_shared<int>(7);
  auto p8 = make_shared<int>(8);
  auto p10 = make_shared<int>(10);
  auto p11 = make_shared<int>(11);

  vector<weak_ptr<int>> v;

  v.push_back(p7);
  v.push_back(p8);

  {
    auto p9 = make_shared<int>(9);
    v.push_back(p9);
    // p9 dtor'd here
  }

  v.push_back(p10);
  v.push_back(p11);
  p8.reset(new int{18}); // old p8 dtor'd here
  p10 = make_shared<int>(110); // old p10 dtor'd here

  // Only 7 and 11 left.

  v.erase(remove_if(v.begin(), v.end(), [](auto w){ if (auto spt = w.lock()) return false; else return true; }), v.end() );
  for (auto w : v)
  {
    cout << "Value is ";
    if (auto s = w.lock())
    {
      cout << *s << "\n";
    }
    else
    {
      cout << "MISSING!\n";
    }
  }
}
Eljay
  • 4,648
  • 3
  • 16
  • 27