Why does std::map crash when it is declared static inline inside a class and used early?

348 Views Asked by At

I have found several times that when a std::map is declared inside a class as a static inline (C++ 17),

struct MyStruct
{
    static inline std::map <A, B> mymap;

    MyStruct(A& a, B& b)
    {
        mymap[a] = b;
    }
};

the MyStruct constructor will crash if it is called early, i.e. before main, inside the first use of the map member.

If the std::map is declared a different way, i.e.,

struct MyStruct
{
    static std::map <A, B>& mymap()
    {
        static std::map <A, B> map;
        return map;
    }
    
    MyStruct(A& a, B& b)
    {
        mymap()[a] = b;
    }
};

then no crash happens.

I would have thought that in both cases the map would be initialized before the call to MyStruct constructor would be allowed to proceed.

Can anyone explain what is happening here?

1

There are 1 best solutions below

0
Sam Varshavchik On BEST ANSWER

Declaring a static inline class member effectively ODR-defines that class member in some randomly-chosen translation unit that forms the final executable.

At this point Static Initialization Order Fiasco becomes a factor when the class member gets referenced in a translation unit in the manner you described.

This results in undefined behavior.

The function-scoped static class instance is a well known technique for defeating the static initialization order fiasco. Function-scoped static objects have well-defined initialization semantics: the first time the function gets called, from any translation unit.