417

If a variable is declared as static in a function's scope it is only initialized once and retains its value between function calls. What exactly is its lifetime? When do its constructor and destructor get called?

void foo() 
{ 
    static string plonk = "When will I die?";
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Motti
  • 110,860
  • 49
  • 189
  • 262

5 Answers5

299

The lifetime of function static variables begins the first time[0] the program flow encounters the declaration and it ends at program termination. This means that the run-time must perform some book keeping in order to destruct it only if it was actually constructed.

Additionally, since the standard says that the destructors of static objects must run in the reverse order of the completion of their construction[1], and the order of construction may depend on the specific program run, the order of construction must be taken into account.

Example

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Output:

C:>sample.exe
Created in foo
Destroyed in foo

C:>sample.exe 1
Created in if
Created in foo
Destroyed in foo
Destroyed in if

C:>sample.exe 1 2
Created in foo
Created in if
Destroyed in if
Destroyed in foo

[0] Since C++98[2] has no reference to multiple threads how this will be behave in a multi-threaded environment is unspecified, and can be problematic as Roddy mentions.

[1] C++98 section 3.6.3.1 [basic.start.term]

[2] In C++11 statics are initialized in a thread safe way, this is also known as Magic Statics.

Community
  • 1
  • 1
Motti
  • 110,860
  • 49
  • 189
  • 262
  • 3
    For simple types with no c'tor/d'tor side effects, it is a straightforward optimization to initialize them in the same manner as global simple types. This avoids the branching, the flag and the order-of-destruction issues. That's not to say their lifetime is any different. – John McFarlane Oct 29 '11 at 01:06
  • 1
    If the function can be called by multiple threads, then does this mean that you need to make sure that static declarations must be protected by a mutex in C++98?? – allyourcode Oct 09 '14 at 00:57
  • @allyourcode, I've updated the answer to refer to C++11, regarding a mutex in C++98, Yep. – Motti Oct 09 '14 at 20:09
  • 1
    "destructors' of global objects must run in the reverse order of the completion of their construction" does not apply here, because these objects are not global. Destruction order of locals with static or thread storage duration is considerably more complicated than pure LIFO, see section 3.6.3 **`[basic.start.term]`** – Ben Voigt Jun 16 '15 at 14:10
  • @BenVoigt, thanks for the correction but from what I see in C++98 it's pretty much LIFO. C++11 complicates things a bit with `thread_local` stuff. – Motti Jun 16 '15 at 14:33
  • 2
    The phrase "at program termination" isn't strictly correct. What about statics in Windows dlls that are loaded and unloaded dynamically? Obviously the C++ standard doesn't deal with assemblies at all (it'd be nice if it did), but a clarification around exactly what the standard does say here would be good. If the phrase "at program termination" was included, it would technically make any implementation of C++ with dynamically unloaded assemblies non-conforming. – Roger Sanders Apr 14 '17 at 12:25
  • 1
    @RogerSanders that's a good point, the standard I have (C++11) says that the destructors of objects with static storage duration _are called as a result of returning from `main` and as a result of calling `std::exit`_. Can you point me to a part of the standard where it allows dynamic libraries explicitly? – Motti Apr 17 '17 at 19:41
  • 2
    @Motti I don't believe the standard does explicitly allow dynamic libraries, but until now I also didn't believe there was anything specifically in the standard that was at odds with its implementation. Of course, strictly speaking the language here doesn't state that static objects can't be destroyed earlier through other means, just that they must be destroyed when returning from main or calling std::exit. A pretty fine line though I think. – Roger Sanders Apr 28 '17 at 00:26
  • 1
    Your first paragraph is only correct for objects with non-vacuous initialization. For other objects (e.g. `static int x = 1;`) the lifetime begins when storage is obtained, which is on program startup for objects of static storage duration (basic.life/1) – M.M Dec 09 '18 at 11:02
134

Motti is right about the order, but there are some other things to consider:

Compilers typically use a hidden flag variable to indicate if the local statics have already been initialized, and this flag is checked on every entry to the function. Obviously this is a small performance hit, but what's more of a concern is that this flag is not guaranteed to be thread-safe.

If you have a local static as above, and foo is called from multiple threads, you may have race conditions causing plonk to be initialized incorrectly or even multiple times. Also, in this case plonk may get destructed by a different thread than the one which constructed it.

Despite what the standard says, I'd be very wary of the actual order of local static destruction, because it's possible that you may unwittingly rely on a static being still valid after it's been destructed, and this is really difficult to track down.

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 77
    C++0x requires that static initialization be thread safe. So be wary but things will only get better. – deft_code Oct 07 '10 at 05:05
  • Destruction order issues can be avoided with a little policy. static/global objects (singletons, etc) shall not access other static objects in their method bodies. They shall only accessed in constructors where a reference/pointer can be stored for later access in methods. This is not perfect but should fix 99 of the cases and cases it doesn't catch are obviously fishy and should be caught in a code review. This is still not a perfect fix as the policy cannot be enforced in the language – deft_code Oct 07 '10 at 05:15
  • I'm a bit of a noob, but why can't this policy be enforced in the language? – cjcurrie Jan 21 '13 at 05:02
  • 10
    Since C++11, this is no longer a problem. Motti's answer is updated according to that. – Nilanjan Basu Dec 28 '17 at 19:24
10

The existing explanations aren't really complete without the actual rule from the Standard, found in 6.7:

The zero-initialization of all block-scope variables with static storage duration or thread storage duration is performed before any other initialization takes place. Constant initialization of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope. Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
8

FWIW, Codegear C++Builder doesn't destruct in the expected order according to the standard.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... which is another reason not to rely on the destruction order!

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 57
    Not a good argument. I would say this is more of an argument not to use this compiler. – Martin York Oct 29 '08 at 19:24
  • 27
    Hmm. If you're interested in producing real-world portable code, rather than just theoretically portable code, I think it's useful to know what areas of the language can cause problems. I'd be surprised if C++Builder was unique in not handling this. – Roddy Oct 29 '08 at 19:58
  • 18
    I'd agree, except that I'd phrase it as "what compilers cause problems, and what areas of the language they do it in" ;-P – Steve Jessop Oct 30 '08 at 00:16
0

The Static variables are come into play once the program execution starts and it remain available till the program execution ends.

The Static variables are created in the Data Segment of the Memory.

Chandra Shekhar
  • 598
  • 1
  • 7
  • 25