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

发布于 2024-10-30 05:30:47 字数 294 浏览 1 评论 0原文

我注意到,如果您在代码中初始化 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 ) ; 
}

I noticed that if you initialize a static variable in C++ in code, the initialization only runs the first time you run the function.

That is cool, but how is that implemented? Does it translate to some kind of twisted if statement? (if given a value, then ..)

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

int main()
{
    go( 5 ) ;
    go( 5 ) ;
    go( 5 ) ; 
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谁的新欢旧爱 2024-11-06 05:30:47

是的,它通常会转换为带有内部布尔标志的隐式 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

Yes, it does normally translate into an implicit if statement with an internal boolean flag. So, in the most basic implementation your declaration normally translates into something like

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

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

  ...
} 

On top of that, if your static object has a non-trivial destructor, the language has to obey another rule: such static objects have to be destructed in the reverse order of their construction. Since the construction order is only known at run-time, the destruction order becomes defined at run-time as well. So, every time you construct a local static object with non-trivial destructor, the program has to register it in some kind of linear container, which it will later use to destruct these objects in proper order.

Needless to say, the actual details depend on implementation.


It is worth adding that when it comes to static objects of "primitive" types (like int in your example) initialized with compile-time constants, the compiler is free to initialize that object at startup. You will never notice the difference. However, if you take a more complicated example with a "non-primitive" object

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

then the above approach with if is what you should expect to find in the generated code even when the object is initialized with a compile-time constant.

In your case the initializer is not known at compile time, which means that the compiler has to delay the initialization and use that implicit if.

玩套路吗 2024-11-06 05:30:47

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

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

Yes, the compiler usually generates a hidden boolean "has this been initialized?" flag and an if that runs every time the function is executed.

There is more reading material here: How is static variable initialization implemented by the compiler?

許願樹丅啲祈禱 2024-11-06 05:30:47

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

ZoogieZork 对 AndreyT 答案的评论涉及到一个重要方面:静态局部变量的初始化 - 关于 <一些编译器包括 GCC - 默认情况下是线程安全的(编译器命令行选项可以禁用它)。因此,它使用某种线程间同步机制(互斥锁或某种原子操作),该机制可能相对较慢。如果您对在函数中显式使用此类操作感到不舒服(性能方面),那么您应该考虑是否有一种影响较小的替代方案来替代变量的延迟初始化(即您自己以线程安全的方式显式构造它)某处仅一次)。很少有函数对性能如此敏感,但这很重要——不要让它破坏你的一天,或者让你的代码变得更复杂,除非你的程序太慢并且你的探查器正在研究这个领域。

While it is indeed "some kind of twisted if", the twist may be more than you imagined...

ZoogieZork's comment on AndreyT's answer touches on an important aspect: the initialisation of static local variables - on some compilers including GCC - is by default thread safe (a compiler command-line option can disable it). Consequently, it's using some inter-thread synchronisation mechanism (a mutex or atomic operation of some kind) which can be relatively slow. If you wouldn't be comfortable - performance wise - with explicit use of such an operation in your function, then you should consider whether there's a lower-impact alternative to the lazy initialisation of the variable (i.e. explicitly construct it in a threadsafe way yourself somewhere just once). Very few functions are so performance sensitive that this matters though - don't let it spoil your day, or make your code more complicated, unless your programs too slow and your profiler's fingering that area.

不必在意 2024-11-06 05:30:47

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

They are initialized only once because that's what the C++ standard mandates. How this happens is entirely up to compiler vendors. In my experience, a local hidden flag is generated and used by the compiler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文