c++ - 如何将管理器的引用传递给处理程序对象?

标签 c++ c++11 memory-management

我想做的是写一个小的Manager/Handler类。管理器分发和管理句柄。例如,这样的句柄可以是一个简单的文件句柄。

如果消费者想要获得一个已经存在的句柄,管理器只需返回一个 shared_ptr。如果句柄不存在,则管理器创建一个新句柄,然后返回 shared_ptr。

在管理器内部,那些 shared_ptr 存储在一个简单的 STL-Map 中。 如果分配的最后一个 shared_ptr 被删除,我希望我的经理删除相关的映射元素,以便处理程序对象自动被破坏。

这听起来有点像垃圾回收(例如工作线程,它检查指针的使用计数),但我相信它可以做得更优雅。

如何将管理器实例的引用传递给处理程序对象? (例如,将 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;
}

最佳答案

您可能希望在管理器中保留非拥有指针以跟踪现有句柄,并使用自定义删除器放弃拥有 shared_ptr。自定义删除器将确保在对象最终被销毁时删除管理器中相应的观察指针。

我将此模式称为 Tracking Factory,它的工作原理如下。给定一个 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 的构造函数是私有(private)的,并且声明了 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;

};

然后,程序的其余部分将通过 object_factory 获取 shared_ptrobject:如果一个对象具有所需的特征(一个id 成员)已经被创建,一个指向它的 shared_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();
}

最后,这是一个live example .

关于c++ - 如何将管理器的引用传递给处理程序对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15707991/

相关文章:

c++ - 存储 wchar_t 并在显示时有时会更改一些字符

c# - 在 CLR 中使用托管线程和纤程

c++ - C++ 项目中的 .pro 扩展名

java - 在 java web 应用程序中,清除任何使用的集合会导致更好的内存管理吗?

c++ - 为什么 x 成员变量不明确?

multithreading - 如何创建运行抽象类的成员函数的 std::thread?

c++ - gcc vs clang 在具有可变参数和相同类型的额外参数的部分特化上的行为

c++ - 如果我忘记在 C++ 中释放内存会发生什么

javascript - 缓存 HTML 字符串或 DOM 元素?

c++ - 未定义的行为 fopen、fclose