Почему следующий код вызывает исключение (в createObjects вызывается map::at
)
Альтернативно код (и его вывод) можно посмотреть здесь
Интересно, что код работает должным образом, если закомментированные строки не закомментированы как с помощью Microsoft, так и компилятора gcc (см. здесь ), это даже работает с initMap в качестве обычной статической переменной вместо статического геттера.
Единственная причина, по которой я могу думать, состоит в том, что порядок инициализации статического объекта registerHelper_ (factory_helper_
) и объекта std::map
(initMap
) неверен, однако я не вижу, как это могло произойти потому что объект карты создается при первом использовании, и это в конструкторе 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;
}