对象为模板时的静态构造
Static Construction when the object is a template
我有一个工厂类,我已经使用了很长一段时间,我试图对它做一些模板魔术,但它根本不起作用。我认为你不需要看到那个类,因为它很大,但如果你真的认为它是相关的,那么我会编辑它。无论如何,我有一个这样的设置,我已经做了很久了。
class Base :
public Factory<Base>
{
};
class Derived :
public Base
{
static Factory<Base>::DerivedRegister<Derived> m_Reg;
};
Factory<Base>::DerivedRegister<Derived> Derived::m_Reg;
工厂为它提供了静态方法createInstance(conststd::string&name),它将返回已注册对象的一个实例。DerivedRegistor对象派生自工厂对象,当静态声明时,必须在静态初始化期间构造。这意味着我可以访问它的构造函数中的工厂静态内部,因此我利用它的构造函数使所有注册的对象在静态初始化期间对工厂可用。这是有效的,而且已经有一段时间了,但后来我尝试了这样的方法,这样派生类就可以避免显式生成静态deriveregister对象:
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类的实例时,它在工厂中并不存在,经过一点涂鸦,我发现静态DerivedRegistor从未在Derived中构造过,就像在构造函数中从未调用过一样。我觉得这很奇怪。如果派生类不是模板,怎么可能不强制它静态初始化呢?当我制作一个伪静态对象,如下所示,并在其静态构造中使用m_Reg中的方法时,DerivedRegistor突然正确构造,工厂可以实例化它,而不需要担心。
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());
那么,关于这个模板类的静态成员初始化,我没有得到什么?它不需要像其他非模板对象一样静态初始化对象吗?
编辑:mkay,为了提供一点见解,我将发布Factory对象。只要小心文字墙。忽略多余的includes、多余的GetNames和func函数,它们只是voodoo代码。
#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
已经构造完成。也就是说,它是在第一次使用的任何时间构建的。
我已经用上面的方法成功地解决了一些棘手的问题,现在我理所当然地使用它,以避免调试奇怪的崩溃。我几乎再也不需要静态成员变量了。
- CPU 瓶颈;处理具有许多非静态对象的 3D 场景渲染的简单方法
- 我可以读取静态对象中的文件.txt吗?C++
- 通过 Gazebo 世界插件将静态对象附加到机器人链接
- 将对象创建为全局/静态对象会崩溃,而本地对象不会崩溃
- 内联函数的函数本地静态对象是否在共享对象文件之间共享?
- 将 C# 对象(包含静态对象成员)作为参数传递给 C++/CLI 程序
- 完全释放静态对象内存
- 静态对象指针
- C++文件中.cpp静态对象声明
- C++类中定义静态对象
- 在初始化类的静态对象之前,是否保证初始化该类的静态成员?
- 静态对象如何调用私有构造函数
- cpp 静态对象实例化
- 等效于 Java 静态对象类C++
- 我怎么知道C++编译器是否制作线程安全的静态对象代码
- 在dlclose()之前破坏的静态对象
- 有没有办法为静态对象成员定义一个符合开关标准的常量?
- c++ 防止类共享静态对象
- 什么时候构造函数为静态对象
- 为什么本地静态对象的初始化使用隐藏的防护标志?