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

时间:2011-04-06 13:55: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 ) ; 
}

4 个答案:

答案 0 :(得分:51)

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

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

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

  ...
} 

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

毋庸置疑,实际细节取决于实施。


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

void go( int x ) {
  static std::string s = "Hello World!";
  ...

然后使用if的上述方法是您应该在生成的代码中找到的内容,即使使用编译时常量初始化对象也是如此。

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

答案 1 :(得分:7)

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

此处有更多阅读材料:How is static variable initialization implemented by the compiler?

答案 2 :(得分:2)

虽然它确实是“某种扭曲的”,但扭曲可能比你想象的更多......

ZoogieZork对AndreyT答案的评论涉及一个重要方面:静态局部变量的初始化 - 某些编译器包括GCC - 默认是线程安全< / strong>(编译器命令行选项可以禁用它)。因此,它使用一些线程间同步机制(某种互斥或原子操作),它可以相对较慢。如果你不熟悉 - 性能明智 - 在你的函数中明确使用这样的操作,那么你应该考虑是否有一个影响较小的替代变量的懒惰初始化(即你自己以线程安全的方式明确地构造它)某处只有一次)。很少有功能对性能如此敏感以至于这一点很重要 - 不要让它破坏你的一天,或者让你的代码变得更复杂,除非你的程序太慢并且你的探测器指的是那个区域。

答案 3 :(得分:1)

它们只被初始化一次,因为这是C ++标准所要求的。如何发生这完全取决于编译器供应商。根据我的经验,编译器会生成并使用本地隐藏标志。