0

I would like some help and an explanation please, I am a bit confused :(

I have a 'weak' manager which holds weak_ptr's to other objects in my program. I would like to know when a weak_ptr becomes expired at the point it becomes expired (i.e the shared_ptr it points to, destructs the item).

I have looked through some interwebs about weak_ptr binding but am I bit confused about it all so any help would be appreciated. I came across this answer (https://stackoverflow.com/questions/11680680/binding-to-a-weak-ptr), but don't really understand it, as I haven't done much with std::bind. How does this work with weak_ptr? If I bind a function to it, does the function get called every time something happens to the weak_ptr?

Essentially I have something like this:

#include <iostream>
#include <list>
#include <memory>
#include <functional>
#include <algorithm>

struct Obj {};

class weakManager
{
public:
    unsigned int addItem(std::shared_ptr<Obj>& item)
    {
        items_.push_back(std::weak_ptr<Obj>(item));
        return items_.size() - 1;
    }

    void addObserver(std::function<void(unsigned int ID)> observer)
    {
        obsevers_.push_back(observer);
    }

    unsigned int getValidItems()
    {
        unsigned int validItems = 0;
        std::for_each(items_.begin(), items_.end(), [&validItems](std::weak_ptr<Obj>& item) 
            {
                if (!item.expired())
                    ++validItems;
            });
        return validItems;
    }

private:
    std::list<std::weak_ptr<Obj>> items_;
    std::list<std::function<void(unsigned int ID)>> obsevers_;
};


int main(int argc, const char * argv[]) 
{
    weakManager manager;

    manager.addObserver([](unsigned int ID) 
        {
            std::cout << "Observer says, item " << ID << " expired...\n";
        });

    {
        std::shared_ptr<Obj> someItem(new Obj);
        std::cout << "Item with ID : " << manager.addItem(someItem) << " added.\n";

        std::cout << "Manager has " << manager.getValidItems() << " valid item(s).\n";
    }
    std::cout << "Manager has " << manager.getValidItems() << " valid item(s).\n";

    return 0;
}

Currently I have to manually check which items in the manager are not expired. I would like to be able to call the 'observer' callback when the item gets destructed (i.e the weak_ptr becomes expired, without a manual call to getValidItems.

Any help would be appreicated. Many thanks.

lfgtm
  • 1,037
  • 6
  • 19
  • you would have to add calling observer to deleter in orign `shared_ptr` of `weak_ptr` to have this kind of behaviour – bartop Oct 11 '19 at 10:16
  • Ok thanks, not enitrely following tbh. Are you saying perhaps I should hold `shared_ptr`'s in the manager and check when the reference counter of the `shared_ptr` hits 1 i.e the one in the manager is the only one left? Rather than having a weak_ptr in the manager? Cheers. – lfgtm Oct 11 '19 at 10:20
  • 1
    No, what I am saying is to have custom deleter for `shared_ptr` you want to check out on. The deleter would call the observers when the object is being deleted (and `weak_ptr`s invalidated) . – bartop Oct 11 '19 at 10:25
  • 1
    No, he's saying the destructor of whatever you're managing should tell the manager that it's destroying itself. – Cubic Oct 11 '19 at 10:25
  • Ok thanks. I see, so it's not possible to have `weak_ptr`'s know when they become expired? Does this mean `shared_ptr`'s are better to be in the manager and `weak_ptr`'s only used by other things. The design of the system is currently not set up this way, as `shared_ptr` owners just create the `shared_ptr` objects and may or may not add them to the manager for others to potentially use. Does this mean when an owner creates the resource, it already needs to know if it is going to be used by the weakManager? problem is the manager doesn't know when it's got a stale item. :( – lfgtm Oct 11 '19 at 10:33
  • "*it's not possible to have `weak_ptr`'s know when they become expired?*" - a `weak_ptr` knows when it is expired. If you try to `lock()` an expired `weak_ptr`, it returns a `shared_ptr` to a null pointer. Also, `weak_ptr` has an `expired()` method you can call directly (`lock()` checks `expired()` internally). – Remy Lebeau Oct 11 '19 at 20:08
  • @RemyLebeau thanks, yes I am familiar with how to use `weak_ptr`'s in this way, however it requires a caller to externally call it to see if it is expired, I would like the `weak_ptr` to invoke some function or to be able to notify some external module at the moment it becomes expired rather than wait for the external module to check if it is expired. – lfgtm Oct 11 '19 at 20:57

0 Answers0