gpt4 book ai didi

c++ - 对象为模板时的静态构造

转载 作者:行者123 更新时间:2023-11-30 04:14:53 26 4
gpt4 key购买 nike

我有一个我已经使用了很长时间的工厂类,我试图对它做一些模板魔术,但它根本行不通。我不认为你需要看那个类(class),因为它很大,但如果你真的认为它相关,那么我会编辑它。无论如何,我有一个像这样的设置,我一直这样做。

class Base :
public Factory<Base>
{
};

class Derived :
public Base
{
static Factory<Base>::DerivedRegister<Derived> m_Reg;
};

Factory<Base>::DerivedRegister<Derived> Derived::m_Reg;

工厂为它提供了静态方法 createInstance(const std::string& name) ,它将返回已注册对象的一个​​实例。 DerivedRegister 对象派生自工厂对象,静态声明时,必须在静态初始化期间构造。这意味着我可以访问它的构造函数中的工厂静态内部结构,因此我利用它的构造函数使所有已注册的对象在静态初始化期间对工厂可用。这有效并且有一段时间了,但后来我尝试了这样的事情,这样派生类就可以避免需要显式地创建静态派生注册对象:

class Base :
public Factory<Base>
{
};

template<class TDerived>
class BaseReg :
public Base
{
static Factory<Base>::DerivedRegister<TDerived> m_Reg;
};

template<class TDerived>
Factory<Base>::DerivedRegister<TDerived> BaseReg<TDerived>::m_Reg;

class Derived :
public BaseReg<Derived>
{
};

当我运行程序并尝试创建 Derived 类的一个实例时,它在工厂中不存在,经过一点点涂鸦,我发现静态 DerivedRegister 永远不会在派生中构造,就像在永远不会调用构造函数。我觉得这很奇怪。如果 Derived 类不是模板,怎么能不强制静态初始化呢?当我制作如下所示的虚拟静态对象,并在其静态构造中使用 m_Reg 中的方法时,DerivedRegister 突然构造正确并且工厂可以实例化它,毫不费力。

class Base :
public Factory<Base>
{
};

template<class TDerived>
class BaseReg :
public Base
{
protected:
static Factory<Base>::DerivedRegister<TDerived> m_Reg;
};

template<class TDerived>
Factory<Base>::DerivedRegister<TDerived> BaseReg<TDerived>::m_Reg;

class Derived :
public BaseReg<Derived>
{
class RandomClass
{
public:
RandomClass(std::string meh) {}
};

private:
static RandomClass m_Obj;
};

Derived::RandomClass Derived::m_Obj(m_Reg.func());

那么我在这里没有得到关于这个模板类的静态成员初始化的什么呢?它不需要像任何其他非模板对象一样静态初始化对象吗?

编辑:好的,为了提供一点见解,我将发布 Factory 对象。请注意文字墙。忽略额外的包含,以及多余的 GetNames 和 func 函数,它们只是巫毒代码。

#ifndef FACTORY_H
#define FACTORY_H

// library tools
#include <map>
#include <string>
#include <typeinfo>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <cxxabi.h>

const std::string demangle(const char* name);

template<class base>
class Factory
{
protected:
template<class T>
static base * createT() { return new T;}

typedef std::map<std::string, base*(*)()> map_type;

static map_type& GetMap()
{
static map_type map;
return map;
}

public:
virtual ~Factory(){}

static base * createInstance(const std::string & s)
{
if(!GetMap().count(s))
return nullptr;
typename map_type::iterator it = GetMap().find(s);
return it->second();
}

template <class TDerived>
struct DerivedRegister :
public Factory<base>
{
DerivedRegister()
{
std::string name = demangle(typeid(TDerived).name());
GetMap().insert(std::pair<std::string, base*(*)()>(name, &createT<TDerived>));
}

DerivedRegister(const std::string& name)
{
GetMap().insert(std::pair<std::string, base*(*)()>(name, &createT<TDerived>));
}

std::string func() {return "meh";}
};

static void GetNames(std::vector<std::string>& names)
{
names.clear();

for(auto it = GetMap().begin(); it != GetMap().end(); ++it)
names.push_back(it->first);

}
};


#endif

最佳答案

假设您正在静态构建工厂本身,或者它是作为其他静态构造链的一部分构建的,您可能会遇到不可预测的静态初始化顺序的问题。

你可以通过在它自己的函数中包装和使用静态来解决这个问题:

template<class TDerived>
class BaseReg :
public Base
{
protected:
static Factory<Base>::DerivedRegister<TDerived> & Reg()
{
static Factory<Base>::DerivedRegister<TDerived> m_Reg;
return m_Reg;
}
};

现在,访问 m_Reg 的唯一方法是调用 Reg(),之后您可以确定 m_Reg 已构建.也就是说,它是在首次使用时构建的。

我已经使用上述方法成功解决了一些棘手的问题,现在我理所当然地使用它,以避免不得不调试奇怪的崩溃。我几乎再也不需要静态成员变量了。

关于c++ - 对象为模板时的静态构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18626498/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com