工厂模式在编译时分配内存,以及如何打印编译时的信息 [英] Factory pattern allocating memory at compile time, and how to print compile time info

查看:122
本文介绍了工厂模式在编译时分配内存,以及如何打印编译时的信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用工厂模式。它基本上允许类在编译时注册并存储在映射中。然后可以使用BaseFactory :: createInstance()返回一个实例



我不知道地图在编译时如何保存类名!



在这种情况下,所有类都是从父类Bump_BaseObject派生的

  // C ++ STL用于添加Reflection 
#include< string>
#include< map>


class Bump_BaseObject;

/ **
*派生基本对象创建工厂
* /
模板< typename T>
Bump_BaseObject * createT(void)
{
#pragma message(createT instantiated)
return new T();
}

struct BaseFactory {
typedef std :: map< std :: string,Bump_BaseObject *(*)()> map_type;

//返回类型's'的实例
static Bump_BaseObject * createInstance(const std :: string& s){
map_type :: iterator it = getMap ) - > find(s);
if(it == getMap() - > end())
return 0;

//这是我们为对象(我们不能有任何参数)instatiate和分配内存的地方
//我们可以写一个接受args的变量,但没有必要。
return it-> gt; second();
}

//检查注册类型的映射中是否存在's'
static bool checkIfRegisteredType(const std :: string& s){
map_type :: iterator it = getMap() - > find(s);
if(it == getMap() - > end())
return false;

return true;
}

protected:
static map_type * getMap(){
// never delete'ed。 (存在,直到程序终止)
//因为我们不能保证正确的销毁顺序
if(!objectMap){objectMap = new map_type; }
return objectMap;
}

private:
static map_type * objectMap;
};

#define VALUE_TO_STRING(x)#x

模板< typename T>
struct DerivedRegister:BaseFactory {
DerivedRegister(const std :: string& s){


#pragma message(Type registered)
getMap ()> insert(std :: pair< std :: string,Bump_BaseObject *(*)()>(s,& createT&
}
};

也有办法打印类名称,因为他们得到注册?

解决方案

我认为你的代码是混乱的,混合预处理器指令与奇怪的继承模式。而不是试图修复它,我想提出一个通用的,自注册的工厂框架(它将打印注册,因为它们发生)。



请注意,所有全局初始化在动态初始化阶段期间发生,即在 main()之前的运行时。



Base.hpp:

  #include< unordered_map> 
#include< string>

class Base
{
public:
typedef Base *(* base_creator_fn)();
typedef std :: unordered_map< std :: string,base_creator_fn> registry_map;

virtual〜Base()= default;

static registry_map& registry();
static Base * instantiate(std :: string const& name);
};

struct注册器
{
注册器(std :: string name,Base :: base_creator_fn func);
};

Base.cpp:

  #includeBase.hpp
#include< iostream>

registry_map& Base :: registry()
{
static registry_map impl;
return impl;
}

Base * Base :: instantiate(std :: string const& name)
{
auto it = Base :: registry名称);
return it == Base :: registry()。end()? nullptr:(it-> second)();
}

注册器:: Registrar(std :: string name,Base :: base_creator_fn func)
{
Base :: registry()[name] = func ;
std :: cout<< 注册类<名称<< '\\\
;
}



使用示例



Example.hpp:

  #includeBase.hpp

class DerivedExample:public Base
{
static注册商;
public:
static Base * create(){return new DerivedExample; }
// ...
};

Example.cpp:

  #includeExample.hpp

注册器DerivedExample :: registrar(DerivedExample,DerivedExample :: create);

Main.cpp

  #includeExample.hpp

int main()
{
Base * p = Base :: instantiate DerivedExample);
Base * q = Base :: instantiate(AnotherExample);
}

这里的关键是每个派生类都有一个静态 Registrar 成员,它在程序的动态初始化阶段被初始化(以未指定的顺序),并且每个构造函数执行到注册表映射的实际插入,以及打印出日志



(如果您没有现代的C ++编译器,使用旧的C ++ 98风格语法:)

  virtual〜Base(){} // no= default 

Base :: registry_map :: const_iterator it = Base :: registry()。find(name); // noauto


I am using the factory pattern. It basically allows classes to be registered at compile time and stored in a map. An instance can then be returned using BaseFactory::createInstance()

I am not sure how a map is holding class names at compile time !! How can memory be allocated in compile time that's valid at run time ?

All class is in this case is derived from the parent class Bump_BaseObject

//C++ STL used for adding Reflection
#include <string>
#include <map>


class Bump_BaseObject;

/**
 * Derived Base objects creation factory
 */
template<typename T>
Bump_BaseObject* createT(void)
{
#pragma message("createT instantiated")
    return new T();
}

struct BaseFactory {
    typedef std::map<std::string, Bump_BaseObject*(*)()> map_type;

    //return an instance of the class type 's'
    static Bump_BaseObject* createInstance(const std::string& s) {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
            return 0;

        //this is where we instatiate and allocate memory for the object(it must NOT have any arguments)
        //we could write a variant that accepts args, but there is no need.
        return it->second();
    }

    //check if 's' is present in the map of registered types
    static bool checkIfRegisteredType(const std::string& s) {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
            return false;

        return true;
    }

protected:
    static map_type* getMap() {
        // never delete'ed. (exist until program termination)
        // because we can't guarantee correct destruction order
        if(!objectMap) { objectMap = new map_type; }
        return objectMap;
    }

private:
    static map_type * objectMap;
};

#define VALUE_TO_STRING(x) #x

template<typename T>
struct DerivedRegister : BaseFactory {
    DerivedRegister(const std::string& s) {


#pragma message("Type registered")
        getMap()->insert(std::pair<std::string, Bump_BaseObject*(*)()>(s, &createT<T>));
    }
};

Also is there a way to print the class names as they get registered ?

解决方案

I think your code is altogether confused, mixing preprocessor directives with strange inheritance patterns. Instead of trying to fix it, I'd like to present a generic, self-registering factory framework (which will print out registrations as they happen).

Note that all global initialization happens during the dynamic initialization phase, i.e. at runtime just before main() is called.

Base.hpp:

#include <unordered_map>
#include <string>

class Base
{
public:
    typedef Base * (*base_creator_fn)();
    typedef std::unordered_map<std::string, base_creator_fn> registry_map;

    virtual ~Base() = default;

    static registry_map & registry();
    static Base * instantiate(std::string const & name);
};

struct Registrar
{
    Registrar(std::string name, Base::base_creator_fn func);
};

Base.cpp:

#include "Base.hpp"
#include <iostream>

registry_map & Base::registry()
{
    static registry_map impl;
    return impl;
}

Base * Base::instantiate(std::string const & name)
{
    auto it = Base::registry().find(name);
    return it == Base::registry().end() ? nullptr : (it->second)();
}

Registrar::Registrar(std::string name, Base::base_creator_fn func)
{
    Base::registry()[name] = func;
    std::cout << "Registering class '" << name << "'\n";
}

Usage Example

Example.hpp:

#include "Base.hpp"

class DerivedExample : public Base
{
    static Registrar registrar;
public:
    static Base * create() { return new DerivedExample; }
    // ...
};

Example.cpp:

#include "Example.hpp"

Registrar DerivedExample::registrar("DerivedExample", DerivedExample::create);

Main.cpp

#include "Example.hpp"

int main()
{
    Base * p = Base::instantiate("DerivedExample");
    Base * q = Base::instantiate("AnotherExample");
}

The crux here is that each derived class has a static Registrar member, which gets initialized (in unspecified order) during the dynamic initialization phase of your program, and each constructor of which performs the actual insertion into the registry map, as well as printing out of the log message.


(If you don't have a modern C++ compiler, you would have to use the old C++98-style syntax:)

virtual ~Base() { }   //  no "= default"

Base::registry_map::const_iterator it = Base::registry().find(name); // no "auto"

这篇关于工厂模式在编译时分配内存,以及如何打印编译时的信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆