gpt4 book ai didi

c++ - (静态初始化/模板实例化)工厂模式的问题

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:32:43 28 4
gpt4 key购买 nike

为什么以下代码会引发异常(在调用 map::at 的 createObjects 中)或者可以查看代码(及其输出)here

有趣的是,如果注释行在 microsoft 和 gcc 编译器(参见 here)中都被取消注释,代码将按预期工作,这甚至可以将 initMap 作为普通静态变量而不是静态 getter 使用。

我能想到的唯一原因是静态 registerHelper_ 对象 (factory_helper_) 和 std::map 对象 (initMap) 是错误的,但是我看不出这是怎么发生的,因为 map 对象是在第一次使用时构造的,而且是在 factory_helper_ 构造函数中构造的,所以一切都应该没问题,不是吗?更令我惊讶的是,那些 doNothing() 行解决了这个问题,因为对 doNothing() 的调用无论如何都会在关键部分(当前失败)通过之后发生。

编辑: 调试显示,如果不调用 factory_helper_.doNothing(),则永远不会调用 factory_helper_ 的构造函数。

#include <iostream>
#include <string>
#include <map>

#define FACTORY_CLASS(classtype) \
extern const char classtype##_name_[] = #classtype; \
class classtype : FactoryBase<classtype,classtype##_name_>

namespace detail_
{
class registerHelperBase
{
public:
registerHelperBase(){}
protected:
static std::map<std::string, void * (*)(void)>& getInitMap() {
static std::map<std::string, void * (*)(void)>* initMap = 0;
if(!initMap)
initMap= new std::map<std::string, void * (*)(void)>();
return *initMap;
}
};

template<class TParent, const char* ClassName>
class registerHelper_ : registerHelperBase {
static registerHelper_ help_;
public:
//void doNothing(){}
registerHelper_(){
getInitMap()[std::string(ClassName)]=&TParent::factory_init_;
}
};
template<class TParent, const char* ClassName>
registerHelper_<TParent,ClassName> registerHelper_<TParent,ClassName>::help_;
}

class Factory : detail_::registerHelperBase
{
private:
Factory();
public:
static void* createObject(const std::string& objclassname) {
return getInitMap().at(objclassname)();
}
};


template <class TClass, const char* ClassName>
class FactoryBase {
private:
static detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> factory_helper_;
static void* factory_init_(){ return new TClass();}
public:
friend class detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName>;
FactoryBase(){
//factory_helper_.doNothing();
}
virtual ~FactoryBase(){};
};

template <class TClass, const char* ClassName>
detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> FactoryBase<TClass,ClassName>::factory_helper_;


FACTORY_CLASS(Test) {
public:
Test(){}
};

int main(int argc, char** argv) {
try {
Test* test = (Test*) Factory::createObject("Test");
}
catch(const std::exception& ex) {
std::cerr << "caught std::exception: "<< ex.what() << std::endl;
}
#ifdef _MSC_VER
system("pause");
#endif
return 0;
}

最佳答案

问题与初始化顺序无关,而是与模板实例化有关。

模板化代码是按需实例化的,也就是说,编译器不会实例化您的程序中未使用的任何模板化代码。特别是,在您的情况下,静态类成员 FactoryBase<>::factory_helper_没有被实例化,因此它不存在于最终的二进制文件中,它没有注册自己......(你可以用 gnu 工具链中的'nm'检查它,这将显示你的可执行文件中存在的符号列表)

尝试更改 FactoryBase构造函数:

template <class TClass, const char* ClassName>
class FactoryBase {
//...
FactoryBase(){
factory_helper_;
}
//...
};

这将强制编译器实际实例化二进制文件中的静态成员,您应该被设置。无需创建空方法并调用它。

编辑:作为对评论的回答,在当前标准的 §14.7.1[temp.inst]/1 段末尾:

Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

关于c++ - (静态初始化/模板实例化)工厂模式的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2851991/

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