henry Asked:2020-11-28 18:37:46 +0000 UTC2020-11-28 18:37:46 +0000 UTC 2020-11-28 18:37:46 +0000 UTC 什么是“静态初始化命令惨败”(SIOF)? 772 什么是“静态初始化命令惨败”(SIOF)? c++ 2 个回答 Voted Best Answer user7860670 2020-11-28T19:00:59Z2020-11-28T19:00:59Z 这是在动态初始化的变量使用其他动态初始化的变量进行初始化时发生的失败。在此示例中,全局变量使用来自另一个翻译单元g_b的全局变量的值进行初始化,此时该g_f翻译单元可能已初始化,也可能未初始化,因为未定义不同翻译单元中变量的动态初始化顺序。在实践中,可能会发现存在此类问题的代码有时可以工作,但有时却不能,这取决于编译器的特性、汇编/链接的顺序。 // Foo.hpp #include <string> struct foo{ ::std::string value; }; foo & Get_GlobalFoo(void); // Foo.cpp #include "foo.hpp" #include <string> static foo g_f{::std::string{"whatever"}}; foo & Get_GlobalFoo(void) { return g_f; } // Bar.hpp #include <string> struct bar{ ::std::string value; }; bar & Get_GlobalBar(void); // Bar.cpp #include "foo.hpp" #include "bar.hpp" static bar g_b{Get_GlobalFoo().value}; bar & Get_GlobalBar(void) { return g_b; } // Main.cpp #include "bar.hpp" #include <iostream> int main() { ::std::cout << Get_GlobalBar().value << ::std::endl; return 0; } 保护自己免受此类问题的影响非常简单 - 永远不要诉诸动态初始化(并同时进行后续销毁)就足够了。简而言之,所有静态变量都必须constexpr和/或通常初始化为零,并且还具有平凡的析构函数。 freim 2020-11-28T19:03:28Z2020-11-28T19:03:28Z 尽管名字很糟糕,但事情很简单。想象一下,我们在不同的源文件中有两个静态变量,其中一个在初始化期间以某种方式引用另一个,例如,它调用了一个类方法。由于未定义静态变量的初始化顺序,因此有 50% 的机会首先初始化因变量,并且这样做会引用尚未初始化的第二个变量。该程序将分别崩溃,而不执行单个语句。这种情况称为 SIOF。 因此,最好不要将类变量设为静态,或者至少确保不会出现这种依赖关系。
这是在动态初始化的变量使用其他动态初始化的变量进行初始化时发生的失败。在此示例中,全局变量使用来自另一个翻译单元
g_b的全局变量的值进行初始化,此时该g_f翻译单元可能已初始化,也可能未初始化,因为未定义不同翻译单元中变量的动态初始化顺序。在实践中,可能会发现存在此类问题的代码有时可以工作,但有时却不能,这取决于编译器的特性、汇编/链接的顺序。保护自己免受此类问题的影响非常简单 - 永远不要诉诸动态初始化(并同时进行后续销毁)就足够了。简而言之,所有静态变量都必须
constexpr和/或通常初始化为零,并且还具有平凡的析构函数。尽管名字很糟糕,但事情很简单。想象一下,我们在不同的源文件中有两个静态变量,其中一个在初始化期间以某种方式引用另一个,例如,它调用了一个类方法。由于未定义静态变量的初始化顺序,因此有 50% 的机会首先初始化因变量,并且这样做会引用尚未初始化的第二个变量。该程序将分别崩溃,而不执行单个语句。这种情况称为 SIOF。
因此,最好不要将类变量设为静态,或者至少确保不会出现这种依赖关系。