2

私がやりたいことは、小さなマネージャー/ハンドラー クラスを作成することです。Manager は、Handle を配布および管理します。このようなハンドルは、たとえば単純なファイルハンドルです。

コンシューマーが既に存在するハンドルを取得したい場合、マネージャーは単純に shared_ptr を返します。ハンドルが存在しない場合、マネージャは新しいハンドルを作成してから、shared_ptr を返します。

Manager 内では、これらの shared_ptr は単純な STL-Map に格納されます。割り当てられた最後の shared_ptr が削除された場合、マネージャーに関連するマップ要素を削除して、ハンドラー オブジェクトが自動的に破棄されるようにします。

これはガベージ コレクション (たとえば、ポインターの使用回数をチェックするワーカー スレッド) のように聞こえますが、よりエレガントに実行できると確信しています。

manager インスタンスの参照を handler オブジェクトに渡すにはどうすればよいですか? (たとえば、unique_ptr(this) を新しいハンドラーのコンストラクターに渡すようなもの)

#include <memory>
#include <iostream>
#include <map>

using namespace std;

/*
 * Simple handler class, that actually does nothing.
 * This could be e.g. a Filehandler class or sth. like that
 */
class Handler {
private:
    int i;
public:
    Handler(int i) :i(i) {}
    ~Handler() {}
    // Say who you are.
    void print(void) { cout << "I am handler # " << i << endl; }
};

/*
 * This is the "manager" class, that manages all handles. A handle is identified
 * by an integer value. If a handle already exists, the Manager returns a shared_ptr,
 * if it does not exist, the manager creates a new handle.
 */
class Manager {
private:
    map<int, shared_ptr<Handler> > handles;
public:
    Manager() {}
    ~Manager() {}

    shared_ptr<Handler> get_handler(int identifier) {
        shared_ptr<Handler> retval;
        auto it = handles.find(identifier);

        if(it != handles.end() ) {
            retval = it->second;
        } else {
            retval = shared_ptr<Handler>(new Handler(identifier));
            handles.insert( pair<int, shared_ptr<Handler>>(identifier, retval) );
        }

        return retval;
    }
};

int main(int argc, char** argv) {
    Manager m;

    // Handler 13 doesn't exist, so it gets allocated
    auto h = m.get_handler(13);
    // Manager knows about handler 13, so it returns the already existing shared_ptr
    auto i = m.get_handler(13);

    h.reset(); // Well... Let's assume we don't need h any more...
    // do some stuff...
    i->print();
    // ...
    i.reset(); // We also loose i. This is exactly the point where i want the manager to forget about the handle 13

    return 0;
}
4

2 に答える 2

5

マネージャーで所有していないポインターを保持して、既存のハンドルを追跡shared_ptrし、カスタムのデリータで所有権を放棄したい場合があります。カスタム デリーターは、オブジェクトが最終的に破棄されるときに、マネージャー内の対応する監視ポインターが確実に削除されるようにします。

私はこのパターンをトラッキング ファクトリーと呼んでいます。objectクラスが与えられた場合(Handlerあなたの場合になります):

class object
{

public:

    size_t get_id() const
    {
        return _id;
    }

private:

    friend class tracking_factory;

    object(size_t id) : _id(id) { }

    size_t _id = static_cast<size_t>(-1);

};

のインスタンスを作成し、それらへのobject非所有参照 ( weak_ptr) を格納するクラスを定義します。このクラスは、 のインスタンスをobject作成できる唯一のクラスです。これが、 のコンストラクターobjectがプライベートであり、アクセスできるようにtracking_factory宣言されている理由です。friend

class tracking_factory
{

public:

    std::shared_ptr<object> get_object(size_t id, 
                                       bool createIfNotFound = true)
    {
        auto i = std::find_if(
            begin(_objects),
            end(_objects),
            [id] (std::pair<size_t const, std::weak_ptr<object>> const& p) 
            -> bool
        {
            return (p.first == id);
        });

        if (i != end(_objects))
        {
            return i->second.lock();
        }
        else if (createIfNotFound)
        {
            return make_object(id);
        }
        else
        {
            return std::shared_ptr<object>();
        }
    }

    size_t count_instances() const
    {
        return _objects.size();
    }

private:

    std::shared_ptr<object> make_object(size_t id)
    {
        std::shared_ptr<object> sp(
            new object(id),
            [this, id] (object* p)
        {
            _objects.erase(id);
            delete p;
        });

        _objects[id] = sp;

        return sp;
    }

    std::map<size_t, std::weak_ptr<object>> _objects;

};

次に、プログラムの残りの部分は を介し​​てshared_ptrs toを取得します: 目的の特性 (ここではメンバー) を持つオブジェクトが既に作成されている場合、新しいオブジェクトがインスタンス化されることなく to it が返されます。機能をテストするためのコードを次に示します。objectobject_factoryidshared_ptr

#include <iostream>

int main()
{
    tracking_factory f;

    auto print_object_count = [&f] ()
    {
        std::cout << "Number of objects: " << f.count_instances() << std::endl;
    };

    print_object_count();

    auto p1 = f.get_object(42);

    print_object_count();

    {
        auto p2 = f.get_object(42);

        print_object_count();

        p1 = f.get_object(0);

        print_object_count();
    }

    print_object_count();

    p1.reset();

    print_object_count();
}

最後に、ライブの例を示します。

于 2013-03-29T17:28:32.167 に答える
2

オブジェクトstd::weak_ptrをマップに保存します。それらは所有権を保持しないため、最後のstd::shared_ptrオブジェクトがなくなるとリソースは破棄されます。std::shared_ptrただし、元のオブジェクトを指すオブジェクトが残っているかどうかを追跡するため、それらをマップに配置すると、そこにまだリソースがあるかどうかを後で確認できます。

于 2013-03-29T17:15:41.930 に答える