【问题标题】:How to implement a static factory pattern in C++如何在 C++ 中实现静态工厂模式
【发布时间】:2015-10-22 22:01:04
【问题描述】:

我尝试使用模板实现静态工厂模式,以 a) 避免为每个派生类编写相同的代码 sn-p,以及 b) 回收相同类型的对象。下面的代码编译但不起作用。不确定这是不是因为我使用了智能指针。

这是我的代码:

class ObjMgr
{
public:
    static ObjMgr & Instance();
    template <typename T>
    void Register(const char* name) {
        m_creators[name] = &(ObjCreator<T>);
    }
    Abstract &
        GetObj(const string& objTypeCode);

private:
    ObjMgr(void) {};

    template <typename T>
    static shared_ptr<Abstract>& ObjCreator() {
        return move(std::shared_ptr<Abstract> (new T));
    }
    typedef shared_ptr<Abstract>& (*PObjCreator)();
    std::unordered_map<std::string, PObjCreator> m_creators;

    vector< shared_ptr<Abstract> > m_objs;

    //singleton
    static unique_ptr<ObjMgr> m_instance;
    static std::once_flag m_onceFlag;
    ObjMgr(const ObjMgr &) = default;
    ObjMgr& operator=(const ObjMgr &) = default;
};

Abstract& ObjMgr::GetObj(const string& objTypeCode)
{
    const shared_ptr<Abstract>& obj = m_creators[objTypeCode]();
    m_objs.push_back(move(obj));

    return *(m_objs.back());
}

代码编译,但在运行时,GetObj 返回了一个空引用。 在main() 中,派生类型注册为

objMgr.Register<Derived>("Derived");

顺便说一句,我使用向量来保存对象,以便以后可以回收相同类型的对象。

谁能告诉我我做错了什么并告诉我如何改正它?

【问题讨论】:

  • 顺便说一句,我使用了一个向量来保存对象,以便以后可以回收相同类型的对象。 -- 那么这是否真的意味着你正在持有向量中用于“稍后回收”的对象的地址?
  • 您能否提供一个可以重现问题的Minimal, Complete, and Verifiable example

标签: c++ static-methods smart-pointers factory-pattern


【解决方案1】:

我发现了问题:对象是在ObjCreator() 的堆栈上创建的。我只需要创建静态变量来保存对象:

template <typename T>
static shared_ptr<Abstract>& ObjCreator() {
    static vector<shared_ptr<Abstract>> objs;
    objs.emplace_back(std::make_shared<T>());
    return (objs.back());
}

然后在ObjMgr我会做记账,看看是否已经存在特定类型的对象,以便我可以回收它。

【讨论】:

    【解决方案2】:

    我认为您的 Register(const char* name) 方法和 unordered_map 可能存在冲突。将 unordered_map 改为 unordered_map

    我无法编译您的代码。

    以下代码有效:

    请注意,我这样做的常用方法是使用 Singleton 模板,因为您似乎总是希望获得相同的实例。

    如果您希望能够返回不同的实例,请更改 ObjectManager::CreatorFunc 中的代码,使“实例”变量不是静态的,而是一个局部变量,或者将不同的 CreatorFunc 传递给 Register。

    stdafx.h:

    #include "targetver.h"
    
    #include <stdio.h>
    #include <tchar.h>
    
    #include <unordered_map>
    #include <memory>
    #include <mutex>
    #include <iostream>
    

    cpp:

    #include "stdafx.h"
    
    class Abstract
    {
    };
    
    template <typename T>
    class Singleton : public Abstract
    {
    private:
        static T* m_singleton;
    
    public:
        static T& Instance()
        {
            if (m_singleton == 0)
            {
                m_singleton = new T();
            }
            return *m_singleton;
        }
    };
    
    template <typename T> T* Singleton<T>::m_singleton;
    
    class ObjectManager : public Singleton<ObjectManager>
    {
    private:
        typedef Abstract& (*CreatorFuncType)();
        std::unordered_map<const char*, CreatorFuncType> m_creators;
    
        template <typename T>
        static T& CreatorFunc()
        {
            static T* const instance = new T();
            return *instance;
        }
    
    public:
        template <typename T>
        void Register(const char* name, CreatorFuncType creator = (CreatorFuncType)CreatorFunc<T>)
        {
            m_creators[name] = creator == 0 ? (CreatorFuncType)Singleton<T>::Instance : creator;
        }
    
        Abstract& ObjectManager::GetObj(const char* name)
        {
            CreatorFuncType creator = m_creators[name];
            return (creator)();
        }
    };
    
    class TestClass : Singleton<TestClass>
    {
        static int count;
    
        int myInstance;
    public:
    
        TestClass()
            : myInstance(++count)
        {
            std::cout << "hello in test class ctor instance #" << myInstance << std::endl;
        }
    
        void TestFunc()
        {
            std::cout << "I'm in the test func with instance #" << myInstance << std::endl;
        }
    };
    
    int TestClass::count = 0;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        ObjectManager::Instance().Register<TestClass>("TestClass");
        TestClass &tc = (TestClass&)ObjectManager::Instance().GetObj("TestClass");
        TestClass &tc2 = (TestClass&)ObjectManager::Instance().GetObj("TestClass");
    
        std::cout << "tc == tc2 is " << (&tc == &tc2 ? "true" : "false") << std::endl;
        std::cout << "tc.... ";
        tc.TestFunc();
        std::cout << "tc2... ";
        tc2.TestFunc();
    
        char buf[100];
        std::cin >> buf;
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-01
      • 2011-07-04
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多