初始化静态字符串成员

c++: initializing static string members

本文关键字:成员 字符串 静态 初始化      更新时间:2023-10-16

我在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 ""

看起来好像我引用的变量(B::str和C::str)还没有初始化。但是我假设当D::str = B::str执行时,C::str最迟初始化,因此D::str也应该保存字符串"id0"。

这是Static Initialization惨败

根据c++标准,如果在不同的转换单元中声明具有静态存储时间的对象,则不指定初始化顺序。

因此任何依赖于这些对象初始化顺序的代码都注定会失败,这个问题在c++中被称为静态初始化惨败

你的代码依赖于B::strC::str的初始化发生在D::str之前的条件,这是标准不保证的。由于这3个静态存储持续时间对象驻留在不同的翻译单元中,它们可以按任意顺序初始化。

如何避免?

解决方案是使用Construct On First use Idiom,简而言之,它意味着用一个通过引用返回对象的全局函数替换全局对象。引用返回的对象应该是local static,因为静态局部对象是在第一次控制流流过它们的声明时构造的,所以对象只会在第一次调用时创建,并且在每次后续调用时都会返回相同的对象,从而模拟您需要的行为。


这应该是一个有趣的阅读:

如何防止"静态初始化顺序惨败"?


静态变量的初始化顺序没有保证。所以不要依赖它。而是使用实际的文字初始化它们,或者更好的方法是,在运行时真正需要它们时初始化它们。