我多次发现,当std::map在类内声明为静态内联(C++17(时,
struct MyStruct
{
static inline std::map <A, B> mymap;
MyStruct(A& a, B& b)
{
mymap[a] = b;
}
};
如果MyStruct构造函数在第一次使用map成员时被提前调用,即在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;
}
};
则不会发生崩溃。
我本以为在这两种情况下,映射都会在允许继续调用MyStruct构造函数之前初始化。
有人能解释一下这里发生了什么吗?
有效地声明static inline
类成员ODR在一些随机选择的翻译单元中定义该类成员,该单元形成最终可执行文件。
在这一点上,当类成员以您描述的方式在翻译单元中被引用时,静态初始化顺序Fiasco成为一个因素。
这会导致未定义的行为。
函数作用域的static
类实例是一种众所周知的技术,用于克服静态初始化顺序的失败。函数范围的static
对象具有定义良好的初始化语义:第一次从任何转换单元调用函数时。