I'm trying to build a simple object factory in c++. So far i have this code:
The Factory:
class Factory{
public:
TCreateMethod = std::function<Simulation*(std::string)>;
public:
Factory() = delete;
static bool Register(const std::string name, TCreateMethod funcCreate){
const auto [it, success] = s_methods.insert({name, funcCreate});
return success;
};
static Simulation* Create(const std::string name, const std::string ini_file){
if (auto it = s_methods.find(name); it != s_methods.end()){
return it->second(ini_file);
}
return nullptr;
};
private:
static std::map<std::string, TCreateMethod> s_methods;
};
std::map<std::string, Factory::TCreateMethod> Factory::s_methods;
The Object:
class SimulationStuff : public Simulation{
public:
SimulationStuff(std::string ini_file);
static Simulation* createMethod(std::string ini_file){
return new SimulationStuff(ini_file);
};
static std::string getFactoryName(){
return "SimulationStuff";
};
private
static bool s_registerd;
};
bool SimulationStuff::s_registered = Factory::Register(SimulationStuff::getFactoryName(), SimulationStuff::createMethod);
Backtrace of the segv:
#0 0x00007ffff75ae44a in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00005555556192a1 in std::_Rb_tree_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > >::operator--() (this=0x7fffffffd820)
at /usr/include/c++/8/bits/stl_tree.h:302
#2 0x0000555555618e36 in std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > > >::_M_get_insert_unique_pos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (this=0x5555557bc180 <Factory::s_methods[abi:cxx11]>, __k="SimulationStuff")
at /usr/include/c++/8/bits/stl_tree.h:2063
#3 0x0000555555618b05 in std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > > >::_M_insert_unique<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > >(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> >&&) (this=0x5555557bc180 <Factory::s_methods[abi:cxx11]>, __v=...)
at /usr/include/c++/8/bits/stl_tree.h:2106
#4 0x00005555556188b2 in std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)>, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> > > >::insert(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)> >&&) (
this=0x5555557bc180 Factory::s_methods[abi:cxx11]>, __x=...) at /usr/include/c++/8/bits/stl_map.h:809
#5 0x00005555556184ab in Factory::Register(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<Simulation* (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)>) (name="SimulationStuff", funcCreate=...)
at src/factory.cpp:13
#6 0x000055555560ca19 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at src/simulation_stuff.cpp:24
#7 0x000055555560ca7e in _GLOBAL__sub_I__ZN28SimulationStuff12s_registeredE () at src/simulation_stuff.cpp:73
#8 0x00005555556c3d75 in __libc_csu_init ()
#9 0x00007ffff71aa02a in __libc_start_main (main=0x55555569f7eb <main(int, char**)>, argc=1, argv=0x7fffffffdb88, init=0x5555556c3d30 <__libc_csu_init>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdb78) at ../csu/libc-start.c:264
#10 0x00005555555a5a6a in _start ()
The Problem I have is that I'm unable to understand why the segv is happening as the s_methods
map should be 0 initialized at compiletime and s_registered
should be initialized at the start of the program.
You've run afoul of the static initialization order fiasco. The order of initialization of objects with static lifetime (such as globals and static class members) that are defined in different compilation units is unspecified. It's entirely possible for
SimulationStuff::s_registered
to be initialized beforeFactory::s_methods
. If that happens then yourstd::map
isn't initialized when you attempt to insert into it.To work around this, construct your registry map on first use. i.e.: