为什么 std::map 在类中声明为静态内联并尽早使用时会崩溃?

Pet*_*her 1 c++ stdmap object-construction

我多次发现,当在类中将 std::map 声明为静态内联(C++ 17)时,

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

    MyStruct(A& a, B& b)
    {
        mymap[a] = b;
    }
};
Run Code Online (Sandbox Code Playgroud)

如果较早调用 MyStruct 构造函数,即在 main 之前、在第一次使用映射成员时调用,它将会崩溃。

如果 std::map 以不同的方式声明,即

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

那么就不会发生崩溃。

我本以为在这两种情况下,都会在允许继续调用 MyStruct 构造函数之前初始化映射。

谁能解释这里发生了什么?

Sam*_*hik 6

static inline有效地声明类成员ODR在形成最终可执行文件的某个随机选择的翻译单元中定义该类成员。

此时,当以您所描述的方式在翻译单元中引用类成员时,静态初始化顺序失败就成为一个因素。

这会导致未定义的行为。

函数范围的static类实例是一种众所周知的技术,可以克服静态初始化顺序的失败。函数范围的static对象具有明确定义的初始化语义:第一次从任何翻译单元调用函数时。