10

我有一个类将weak_ptr 存储在容器中,如果weak_ptr 未过期,稍后会执行一些操作:

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

如果Example是一个永远存在并fill定期使用的对象,则向量会不断为元素分配内存,但它们在过期后永远不会被删除。

是否有任何自动 C++ 方法来摆脱容器中过期的weak_ptrs,或者是否有更好的方法来存储可变数量的它们?

fill我幼稚的方法是每次调用容器时都遍历容器并删除所有过期的weak_ptrs。在容器中有许多元素并且经常调用填充的情况下,Example这似乎非常低效。

4

3 回答 3

5

由于您澄清了您实际上使用的是 astd::map而不是 a std::vector,因此在doSomething(). 从基于范围的 for 循环切换回基于常规迭代器的设计:

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;
    }
}
于 2013-09-27T21:05:08.553 回答
2

我宁愿为 shared_ptr 使用自定义删除器。但这意味着这里要更改 Example 类的接口。使用自定义删除器的优点是无需检查集合中的过期对象。该集合由自定义删除器直接维护。

快速实施:

#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();
}
于 2013-09-28T11:23:11.660 回答
2

shared_ptr<int>必须是一个吗shared_ptr<int>

怎么样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;
}
于 2013-09-27T21:11:04.117 回答