Search code examples
c++c++11weak-ptr

How to get rid of weak_ptrs in a container


I have a class that stores weak_ptrs in a container and later does something if the weak_ptr is not expired:

class Example
{
public:
    void fill(std::shared_ptr<int> thing)
    {
        member.push_back(thing);
    }
    void dosomething() const
    {
        for (const auto& i : member)
            if (!i.expired())
                ;// do something. the weak_ptr will not be locked
    }
private:
    std::vector<std::weak_ptr<int>> member;
};

If Example is an object that lives forever and fill is used regularily, the vector allocates memory for elements continously, but they are never removed after they expired.

Is there any automatic C++ way to get rid of the expired weak_ptrs in the container or is there a better way to store a variable number of them?

My naive way would be to iterate over the container each time fill is called and remove all the expired weak_ptrs. In scenarios where Example has many elements in the container and fill is frequently called this seems to be very inefficient.


Solution

  • Does the shared_ptr<int> have to be a shared_ptr<int>?

    How about a shared_ptr<IntWrapper>?

    #include <iostream>
    #include <forward_list>
    using namespace std;
    
    class IntWrapper {
    public:
        int i;
    
        static forward_list<IntWrapper*>& all() {
            static forward_list<IntWrapper*> intWrappers;
            return intWrappers;
        }
        IntWrapper(int i) : i(i)  {
            all().push_front(this);
        }
        ~IntWrapper() {
            all().remove(this);
        }
    };
    
    void DoSomething() {
        for(auto iw : IntWrapper::all()) {
            cout << iw->i << endl;
        }
    }
    
    int main(int argc, char *argv[]) {
        shared_ptr<IntWrapper> a = make_shared<IntWrapper>(1);
        shared_ptr<IntWrapper> b = make_shared<IntWrapper>(2);
        shared_ptr<IntWrapper> c = make_shared<IntWrapper>(3);
        DoSomething();
        return 0;
    }