How to get rid of weak_ptrs in a container

旧城冷巷雨未停 提交于 2019-12-01 18:07:10

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;
}

Since you clarified that you are actually using a std::map and not a std::vector, it might be easiest to remove the expired elements on-the-fly in doSomething(). Switch back from a range-based for loop to a normal iterator based design:

void dosomething() const
{
    auto i = member.begin();
    while( i != member.end() ) {
      if( i->expired() ) { i = member.erase( i ); continue; }
      ;// do something. the weak_ptr will not be locked
      ++i;
    }
}

I would rather use a custom deleter for the shared_ptr. But this implies here to change the interface of the Example class. The advantage using custom deleter is that there is no need to check for expired objects in the collection. The collection is directly maintained by the custom deleter.

Quick implementation :

#include <memory>
#include <iostream>
#include <set>

template <typename Container>
// requires Container to be an associative container type with key type
// a raw pointer type
class Deleter {
    Container* c;
public:
    Deleter(Container& c) : c(&c) {}
    using key_type = typename Container::key_type;
    void operator()(key_type ptr) {
        c->erase(ptr);
        delete ptr;
    }
};

class Example {
public:
    // cannot change the custom deleter of an existing shared_ptr
    // so i changed the interface here to take a unique_ptr instead
    std::shared_ptr<int> fill(std::unique_ptr<int> thing) {
        std::shared_ptr<int> managed_thing(thing.release(), Deleter<containter_type>(member));
        member.insert(managed_thing.get());
        return managed_thing;
    }

    void dosomething() const {
        // we don't need to check for expired pointers
        for (const auto & i : member)
            std::cout << *i << ", ";

        std::cout << std::endl;
    }

    using containter_type =  std::set<int*>;
private:
    containter_type member;
};

int main()
{
    Example example;
    auto one = example.fill(std::unique_ptr<int>(new int(1)));
    auto two = example.fill(std::unique_ptr<int>(new int(2)));
    auto three = example.fill(std::unique_ptr<int>(new int(3)));
    example.dosomething();
    three.reset();
    example.dosomething();
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!