56

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 ) ; 
}
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
bobobobo
  • 64,917
  • 62
  • 258
  • 363

4 Answers4

60

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 2
    I thought static's were really global, which is why they are shared between threads... And being global, they are initialized only once... – dicroce Apr 06 '11 at 14:00
  • 3
    @dicroce, static variables inside functions are different from real globals: they are initialized lazily, upon the first call of the enclosing function. Hence you need some form of check within the function. – Péter Török Apr 06 '11 at 14:02
  • 1
    @dicroce: Local statics are initialized *at most* once. But it is not known in advance *when* they will get initialized. And they might not get initialized at all (if the control never runs over the declaration). – AnT stands with Russia Apr 06 '11 at 14:04
  • 1
    @dicroce: You may be interested in the discussion about local statics and threadsafety (or lack thereof in certain implementations) in this other question: http://stackoverflow.com/questions/1270927/are-function-static-variables-thread-safe-in-gcc – ZoogieZork Apr 06 '11 at 14:06
  • @AndreyT: And how does it ensure that `j_initialized` is initialized once? – Nawaz Apr 06 '11 at 14:18
  • @Nawaz: `j_initialized` doesn't have dynamic initialization, only static. Which means that it will be statically initialized when the executable (or dynamic object) is loaded into memory. – James Kanze Apr 06 '11 at 14:23
  • @Nawaz: `j_initialized` is implicitly initialized with a compile-time constant (`false`). Such initialization is done only once at startup. Easy. The problem with `j` is that its initializer is not a compile-time constant. Which is specifically why the compiler is forced to delay the initialization of `j` and use the `if` trick. – AnT stands with Russia Apr 06 '11 at 15:44
  • @AndreyT: The last comment makes everything clear. I think I understood it better now. Thanks for the explanation. +1 – Nawaz Apr 06 '11 at 15:51
  • Wait a minute, shouldn't those be _nonstatic_ variables in your example? Because then there'd be 2 more variables to keep track of _those_ static's initialization.. – bobobobo Jun 22 '12 at 12:44
  • @bobobobo: No, they should be *static*. (How would it work if they weren't?) As I said in the previous comment and in the answer itself, these extra static variables are objects of *primitive* types (`bool`) initialized with *compile time* constants (`false`). Such objects are initialized at program startup. There's no need and no reason to keep track of their initialization at all. Again, the only case when we need this `if` trick is when it is either a non-trivial object and/or when the initializer is a tun time value. – AnT stands with Russia Jun 22 '12 at 15:06
  • Ok wait no then shouldn't they be declared outside the function body? – bobobobo Jun 24 '12 at 17:45
  • @bobobobo: You can go that way, but why? For primitive types outside or inside makes no difference whatsoever. Declaring them inside limits their visibility, but makes no other difference at all. You can declare them outside if you want, making sure that the names are unique. That will also work. Declaring them inside just looks more elegant. – AnT stands with Russia Jun 25 '12 at 01:43
  • 1
    I think it is possible for a compiler to avoid the if when j_initialized is not known at compile time. If two versions of function go is generated, one without the "if", the reference to go can be replaced once the variable is initialized. Am I right? Probably not worth for most cases. And the number of generated functions increase fast as more static variables are introduced. – Joelmob Dec 09 '16 at 02:34
  • 1
    @Joelmob: In theory, yes you are right. However, replacing the target of a direct function call at run time would require either 1) implementing it as an indirect call, which is less efficient and non-inlinable, or 2) making a direct modification of the executable code, which is also very problematic. I'm not aware of any compilers that would attempt something like that. It does not seem to be worth it. – AnT stands with Russia Dec 09 '16 at 04:46
8

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?

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
3

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.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • `on some compilers` is wrong: it's **mandatory** that static initialisation be thread-safe. see: http://stackoverflow.com/q/8102125/2757035 – underscore_d Jan 24 '17 at 20:53
  • 4
    @underscore_d: this answer was written for C++03, if you want to say things changed as of C++11 knock yourself out.... – Tony Delroy Feb 16 '17 at 06:45
1

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.

Jeffrey Faust
  • 547
  • 3
  • 12