什么使静态变量只初始化一次?

bob*_*obo 46 c++ variables static static-variables

我注意到如果在代码中初始化C++中的静态变量,初始化仅在您第一次运行该函数时运行.

这很酷,但是如何实现?它是否转化为某种扭曲的if语句?(如果给出一个值,那么..)

void go( int x )
{
    static int j = x ;
    cout << ++j << endl ; // see 6, 7, 8
} 

int main()
{
    go( 5 ) ;
    go( 5 ) ;
    go( 5 ) ; 
}
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 51

是的,它通常会转换为if带有内部布尔标志的隐式语句.因此,在最基本的实现中,您的声明通常会转换为类似的内容

void go( int x ) {
  static int j;
  static bool j_initialized;

  if (!j_initialized) {
    j = x;
    j_initialized = true;
  }

  ...
} 
Run Code Online (Sandbox Code Playgroud)

最重要的是,如果您的静态对象具有非平凡的析构函数,则该语言必须遵循另一个规则:这些静态对象必须按其构造的相反顺序进行破坏.由于构造顺序仅在运行时已知,因此销毁顺序也在运行时定义.因此,每次使用非平凡的析构函数构造本地静态对象时,程序必须将其注册到某种线性容器中,以后它将用于按正确的顺序销毁这些对象.

不用说,实际细节取决于实施.


值得补充的是,当涉及int使用编译时常量初始化的"原始"类型的静态对象(如在您的示例中)时,编译器可以在启动时自由地初始化该对象.你永远不会注意到差异.但是,如果您使用"非原始"对象采用更复杂的示例

void go( int x ) {
  static std::string s = "Hello World!";
  ...
Run Code Online (Sandbox Code Playgroud)

那么上面的方法if就是你应该期望在生成的代码中找到的东西,即使用编译时常量初始化对象也是如此.

在您的情况下,初始化程序在编译时是未知的,这意味着编译器必须延迟初始化并使用隐式if.

  • @dicroce,函数内部的静态变量与实际全局变量不同:它们在第一次调用封闭函数时被懒惰地初始化.因此,您需要在函数内进行某种形式的检查. (3认同)
  • 我认为静态是真正的全局,这就是为什么它们在线程之间共享......而且作为全局,它们只被初始化一次...... (2认同)

Jon*_*Jon 7

是的,编译器通常会生成一个隐藏的布尔值"这已被初始化了吗?" 标志和if每次执行函数时运行的标志.

这里有更多的阅读材料:编译器如何实现静态变量初始化?