1

我正在尝试用 C++ 构建一个简单的对象工厂。到目前为止,我有这个代码:

工厂:

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;

物体:

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);

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 ()

我遇到的问题是我无法理解为什么会发生 segv,因为s_methods映射应该在编译时初始化为 0,并且s_registered应该在程序开始时初始化。

4

1 回答 1

0

您与静态初始化命令fiasco 发生冲突。未指定在不同编译单元中定义的具有静态生命周期的对象(例如全局变量和静态类成员)的初始化顺序。SimulationStuff::s_registered之前初始化是完全可能的Factory::s_methods。如果发生这种情况,那么std::map当您尝试插入它时,您不会被初始化。

要解决此问题,请在首次使用时构建您的注册表映射。IE:

class Factory {
        // ...
        static std::map<std::string, TCreateMethod>& getMethods() {
            static std::map<std::string, TCreateMehtod> methods;
            return methods;
        }

        static bool Register(const std::string name, TCreateMethod funcCreate){
            const auto [it, success] = getMethods().insert({name, funcCreate});
            return success;
        };
        // ...
};
于 2020-05-24T19:27:58.277 回答