10

コンテナーに weak_ptrs を格納し、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、ベクトルは要素にメモリを継続的に割り当てますが、有効期限が切れた後に要素が削除されることはありません。

コンテナ内の期限切れのweak_ptrsを自動的に取り除くC++の方法はありますか、それともそれらの可変数を保存するより良い方法はありますか?

私の素朴な方法は、呼び出されるたびにコンテナーを反復処理しfill、期限切れのすべてのweak_ptrsを削除することです。コンテナ内に多くの要素があり、fill が頻繁に呼び出されるシナリオでExampleは、これは非常に非効率的です。

4

3 に答える 3

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 に答える
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 に答える