我在c ++中初始化静态字符串成员时遇到了一些问题.我有几个类,每个类都有几个代表id的静态字符串成员.当我通过调用静态函数初始化变量时,一切都很好.但是,当我想要为另一个变量赋值时,它仍然保留空字符串.这段代码有什么问题?
std::string A::id()
{
std::stringstream sst;
sst << "id" << i;
i++;
return sst.str();
}
std::string B::str = A::id(); //prints "id0";
std::string C::str = "str"; //prints str
std::string D::str = B::str; //prints "" <-- what's wrong here?
std::string D::str2 = C::str; //prints ""
Run Code Online (Sandbox Code Playgroud)
似乎我所引用的变量(B :: str和C :: str)尚未初始化.但我假设当执行D :: str = B :: str时C :: str最迟被初始化,因此D :: str也应该保存字符串"id0".
Alo*_*ave 10
这是静态初始化Fiasco.
根据C++标准,如果在不同的翻译单元中声明具有静态存储持续时间的对象的初始化顺序,则不指定.
因此,依赖于这些对象的初始化顺序的任何代码都必然会失败,并且这个问题在C++中被称为静态初始化Fiasco.
您的代码依赖于Initialized of B::str
和C::str
之前发生的条件D::str
,这是标准无法保证的.由于这3个静态存储持续时间对象位于不同的转换单元中,因此可以按任意顺序初始化它们.
怎么避免呢?
解决方案是使用Construct On First Use Idiom,简而言之,它意味着用全局函数替换全局对象,该函数通过引用返回对象.引用返回的对象应该是本地静态的,因为静态本地对象是在第一次控制流过它们的声明时构造的,所以只在第一次调用时创建对象,并且在每次后续调用时都会返回相同的对象,从而模拟你需要的行为.
这应该是一个有趣的读物: