Pourquoi est-ce de code suivant soulèvent une exception (en createObjects appel à map::at
) alternativly le code (et sa sortie) peut être vu here(initialisation statique/instanciation de modèle) problèmes avec motif d'usine
intererestingly le code fonctionne comme Si les lignes commentées sont décommentées avec les compilateurs microsoft et gcc (voir here), cela fonctionne même avec initMap en tant que variable statique ordinaire au lieu de getter statique.
La seule raison que je peux penser est que l'ordre d'initialisation de l'objet registerHelper_ statique (factory_helper_
) et l'objet std::map
(initMap
) ont tort, mais je ne peux pas voir comment cela pourrait se produire, parce que l'objet carte est construit à la première utilisation et c'est dans factory_helper_ constructor, donc tout devrait bien se passer, n'est-ce pas? Je suis encore plus surpris que ces lignes de doNothing() corrigent le problème, parce que cet appel à doNothing() se produirait après que la section critique (qui échoue actuellement) soit passée de toute façon.
EDIT: Le débogage a montré que sans l'appel à factory_helper_.doNothing(), le constructeur de factory_helper_ n'est jamais appelé.
#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;
}
Ajoutez une partie de l'impression de débogage à vos constructeurs et à vos fonctions d'accesseur, voir quels objets sont créés et quand. –