Search

6.10 — Static local variables

The term static is one of the most confusing terms in the C++ language, in large part because static has different meanings in different contexts.

In prior lessons, we covered that global variables have static duration, which means they are created when the program starts and destroyed when the program ends.

We also discussed how the static keyword gives a global identifier internal linkage, which means the identifier can only be used in the file in which it is defined.

In this lesson, we’ll explore the use of the static keyword when applied to a local variable.

Static local variables

In lesson 2.4 -- Introduction to local scope, you learned that local variable have automatic duration by default, which means they are created at the point of definition, and destroyed when the block is exited.

Using the static keyword on a local variable changes its duration from automatic duration to static duration. This means the variable is now created at the start of the program, and destroyed at the end of the program (just like a global variable). As a result, the static variable will retain its value even after it goes out of scope!

The easiest way to show the difference between automatic duration and static duration variables is by example.

Automatic duration (default):

Each time incrementAndPrint() is called, a variable named value is created and assigned the value of 1. incrementAndPrint() increments value to 2, and then prints the value of 2. When incrementAndPrint() is finished running, the variable goes out of scope and is destroyed. Consequently, this program outputs:

2
2
2

Now consider the static version of this program. The only difference between this and the above program is that we’ve changed the local variable from automatic duration to static duration by using the static keyword.

Static duration (using static keyword):

In this program, because s_value has been declared as static, s_value is created and initialized once (at program start). If we were not using a constant expression to initialize s_value, it would be zero-initialized at program start and then initialized with our supplied initialization value the first time the variable definition is encountered (but it is not reinitialized on subsequent calls).

When s_value goes out of scope at the end of the function, it is not destroyed. Each time the function incrementAndPrint() is called, the value of s_value remains at whatever we left it at previously. Consequently, this program outputs:

2
3
4

Just like we use “g_” to prefix global variables, it’s common to use “s_” to prefix static (static duration) local variables.

One of the most common uses for static duration local variables is for unique ID generators. Imagine a program where you have many similar objects (e.g. a game where you’re being attacked by many zombies, or a simulation where you’re displaying many triangles). If you notice a defect, it can be near impossible to distinguish which object is having problems. However, if each object is given a unique identifier upon creation, then it can be easier to differentiate the objects for further debugging.

Generating a unique ID number is very easy to do with a static duration local variable:

The first time this function is called, it returns 0. The second time, it returns 1. Each time it is called, it returns a number one higher than the previous time it was called. You can assign these numbers as unique IDs for your objects. Because s_itemID is a local variable, it can not be “tampered with” by other functions.

Static variables offer some of the benefit of global variables (they don’t get destroyed until the end of the program) while limiting their visibility to block scope. This makes them safe for use even if you change their values regularly.

Overusing static local variables

Consider the following code

Sample output

Enter an integer: 5
Enter another integer: 9
5 + 9 = 14

This code does what it’s supposed to do, but because we used a static local variable, we made the code harder to understand. If someone reads the code in `main()` without reading the implementation of `getInteger()`, they’d have no reason to assume that the two calls to getInteger() do something different. But the two calls do something different, which can be very confusing if the difference is more than a changed prompt.

Say you press the +1 button on your microwave and the microwave adds 1 minute to the remaining time. Your meal is warm and you’re happy. Before you take your meal out of the microwave, you see a cat outside your window and watch it for a moment, because cats are cool. The moment turned out to be longer than you expected and when you take the first bite of your meal, it’s cold again. No problem, just put it back into the microwave and press +1 to run it for a minute. But this time the microwave adds only 1 second and not 1 minute. That’s when you go “I changed nothing and now it’s broken” or “It worked last time”. If you do the same thing again, you’d expect the same behavior as last time. The same goes for functions.

Suppose we want to add subtraction to the calculator such that the output looks like the following

Addition
Enter an integer: 5
Enter another integer: 9
5 + 9 = 14
Subtraction
Enter an integer: 12
Enter another integer: 3
12 - 3 = 9

We might try to use getInteger() to read in the next two integers like we did for addition.

But this won’t work, the output is

Addition
Enter an integer: 5
Enter another integer: 9
5 + 9 = 14
Subtraction
Enter another integer: 12
Enter another integer: 3
12 - 3 = 9

(“Enter another integer” instead of “Enter an integer”)

getInteger() is not reusable, because it has an internal state (The static local variable isFirstCall) which cannot be reset from the outside. isFirstCall is not a variable that should be unique in the entire program. Although our program worked great when we first wrote it, the static local variable prevents us from reusing the function later on.

A better way of implementing getInteger is to pass isFirstCall as a parameter. This allows the caller to choose which prompt will be printed.

Static local variables should only be used if in your entire program and if the foreseeable future of your program, the variable is unique and it wouldn’t make sense to reset the variable.

Best practice

Avoid static local variables unless the variable never needs to be reset. static local variables decrease reusability and make functions harder to reason about.

Quiz time


Question #1

What effect does using keyword static have on a global variable? What effect does it have on a local variable?

Show Solution


6.11 -- Scope, duration, and linkage summary
Index
6.9 -- Why global variables are evil

134 comments to 6.10 — Static local variables

  • The blurb about avoiding their (static local variables) usage is really small, and the rest of the article only talks about how they can be good. I guess: what is the alternative to static local variables, and I wish there was more detail about why they were bad (although the reasons listed aren't vague or anything).

  • Shasha

    Can we use static local variables outside their block scope? Or the static keyword only changes the duration from automatic to static?

    • I'm also a little confused, but this is how I think it works:

      The static local variable, still having block scope, can't be directly referenced by other code, but the function it is used in can be called (as in the example above).
      But the value of the variable is not destroyed after exiting the block(/function), and still exists ("floating around" in the memory")

  • Raj

    "Avoid static local variables, unless the variable never needs to be reset".  This statement is most confusing and has only negative elements. Instead it could have been written as
    " Use static local variables, if variable never resets".

  • Math

    Hello, I have been loving those tutorials so much :)
    C++ is my first language to start learning and I am still at the very beginning. These tutorials showed me just how much there is to this language and not gonna lie I think c++ will forever be my favorite language. Thank you so much for these tutorials.
    However, as I am reading I am learning a lot sure but I mostly don't use everything I learn and this is honestly bothering me quite a lot. For example, I have never used global variables and almost never have to define my own namespace, my programs are just far too simple. How do you suggest I make the most out of these tutorials while still being a beginner?

    • lycanthoss

      By far the best way to learn programming is to just do projects and actually make something. Programming is focused a lot more on practice than theory. Typical programming projects for beginners include: Snake game, Tic-Tac-Toe, todo list, calculator. But these things should only be attempted when you know the more important stuff like arrays and loops.

  • Gowtam

    Hey,

    > return s_itemID++; // makes copy of s_itemID, increments the real s_itemID, then returns the value in the copy

    Where is the copy is stored? in another variable or in a register?

  • Slyminc

    Hi Alex! Hi Nascar!

    in static local variable example (the one with static keyword), you said that, "If we were not using a constant expression to initialize s_value, it would be zero-initialized at program start and then..."

    why would we need const to initialize static on local variable? that's two different world right? const make variable value unchangeable, while static keyword on local variable make it static duration, and also changeable (because the value can adds up while we incrementing or decrement this variable while it's still runtime). is there something i miss here? thanks.

    • nascardriver

      A "constant expression" is a value that's known at compile-time, for example a literal (1, in this case). When a `static` variable is initialized with a constant expression, the compiler can place the value in the binary already. Without a constant expression, the compiler wouldn't know the value, so the memory gets initialized to 0 and the correct value is loaded at run-time.

  • kuukerin nelli

    if we wanted ID's starting from 0, wouldn't a more efficient way of doing so be

    • Alex

      Sure, but I find this a little harder to read since the meaning of the -1 isn't obvious until you think about it, so there's a tradeoff there.

  • Fan

    In the part on static local variables you said that they are created when the program starts, but cppreference says they are created when execution passes the definition for the first time. I tried the code

    and the print out is:

    Main called
    Ctor called
    Hello
    Hello

  • Jimmy Hunter

    Left out the word "be"

    Typo ==> "If you notice a defect, it can near impossible to distinguish which object is having problems."
    Correction ==> "If you notice a defect, it can be near impossible to distinguish which object is having problems."

  • Tom Bauer

    So, if you call a funktion that creates a static variable again and again it doesnt matter that the variable is created over and over again? Or is it just created once in global scope and the other "creations" are ignored?

    • AbraxasKnister

      Freely interpreted from what the text after the second code snippet says about the lifecycle of a static local variable: (a) It gets created and initialized to 0 at program startup (b) its value is overridden by the value given at the variable definition at first encounter (ie. at the time the respective function is called the first time) (c) in subsequent calls its definition statement is effectively ignored (d) at termination of the function the variables value is stored (e) subsequent function calls function as if the variable was defined with precisely the value that was stored for it the last termination. TL;DR yes. (to 2nd question)

  • koe

    In the next section it mentions that static local variables are instantiated at program startup. Is this accurate, and if so does it mean all static local variables will be created regardless of if their block is actually executed?

    • nascardriver

      `static` variables are created at program startup. Creation means memory reservation, but not initialization. Local `static` variables are initialized when they are first encountered during execution, but their memory already existed. Global `static` variables are initialized at program-startup.
      If you declare a local `static` variable but execution doesn't reach it, you still used the memory (But never initialized it).

      • koe

        The chapter says "In this program, because s_value has been declared as static, s_value is created (and zero-initialized) once (at program start)". Is it actually zero-initialized, or is the memory content undefined until its definition line gets executed the first time?

        • nascardriver

          `static` variables are initialized. What bothers me is the "zero-initialized" part. If `s_value` was initialized with a non-constant expression, this would be true. But `1` is a constant expression, so `s_value` will be initialized to `1` right away, `s_value` never is 0. I updated the lesson.

  • Arush Agarampur

    When I make a class like

    I must do

    to initialize and access it. I understand how to do it, but why do I have to do it? And what is this called?

    • nascardriver

      Line 3 is only a declaration of `IntVal`, not a definition. You can't define it in the header, because every file that includes the header would defined `IntVal`. That's a violation of the one-definition-rule.
      `int C::IntVal{ 0 };` is the definition of `IntVal`. It goes in the source file that corresponds to the header `C` was declared in. The source file only gets compiled once, so you don't get multiple definitions.

  • NooneAtAll

    Patiently waiting for addition of constinit to this page...

    • nascardriver

      `constinit` will probably be added alongside `constexpr` functions.
      `constexpr` functions will not be covered before C++20 is available in the major compilers, because C++20 lifted many restrictions on `constexpr` functions.

      I haven't used `constinit` yet, but as far as I can tell it doesn't change a whole lot. You should be able to understand it from reading its documentation.

      • NooneAtAll

        ha, you fell for this just like me

        functions can be const**eval**  
        const**init** is to make static variables be calculated at compile time, instead of first call of function

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    Does right if constexpr/const is actually static(by default) global variable?

  • Anonymous

    Why are global variables evil while static aren't?

    • Alex

      Static local variables are scoped to the local functions in which they are declared.

      It's not the persistence that's evil, it's the broad accessibility by anyone that's evil.

  • error

    I think there is a typo here ( 2nd paragraph to the last): " Because s_itemID is a local variable, it can not be “tampered with” by other functions."

    s_itemID is a static variable, not a local variable...is it not?

    • Kodnot

      Nope, not a typo. s_itemID is a static local variable - static duration, local scope. And it cannot be "tampered with" by other functions due to its local scope, while retaining its value between function calls due to its static duration.

  • Now the "static" keyword the way it's explained here was something that really surprised me when I was taking courses like these about C. C was the first language of which I found out they are supported (although since C and C++ are the only language for which I am actually reading these very detailed tutorials I may have missed stuff in other languages), so I guess I may have used a lot of globals in the past which would better have served as 'static' variables.

    Now I began coding when I was 8 or 9 or so, and now I'm in my forties, and old habits die hard, so I guess, I might be guilty of the crime for using unneeded globals awhile longer :P

  • Puya

    Hi Alex,

    I think this might be a typo "automatic duration [means] they are created when the block is entered", since in 4.1a it says: "automatic duration [means] they are [created] at the point of definition". (which would be different if your definition is not at the top of your block)
    e.g.

    • Alex

      It's more correct to say they're created at the point of definition. I've updated this article accordingly. Thanks for pointing out the mismatch.

  • Benur21

    1)

    If I do like this it will only execute the first (0)?

    2)
    When doing

    , if a previous static int s_itemID is accessible (in the right scope) it does not execute; and if s_itemID is not accessible (in some other scope or not created at all) it will execute?

    3)
    Does "static int s_value" conflict with other previously created variables in outside blocks, as well as with variables of different types with same name?

  • Codename 47

    Hey Alex,

    Only for the sake of consistency -- in the first two examples in this tutorial, the function int main() does not have any return statement.

  • diksha chadha

    Hi,

    I have a doubt in the line :
    Static variables offer some of the benefit of global variables (they don’t get destroyed until the end of the program) "while limiting their visibility to block scope". This makes them much safer for use than global variables.

    And in 8.11 it is said : Note that this static member definition is not subject to access controls: you can define and initialize the value even if it’s declared as private (or protected) in the class.

    Could you please explain the difference in the two.

    • Alex

      Two different things entirely. The static variables in this lesson are for non-members, the ones in 8.11 are for static members.

      Non-member static variables are typically defined in a function. They retain their value across function calls, but can't be accessed outside the function.
      Member static variables are defined inside a class. Although normal private or protected members can't be accessed directly from outside the class, a static member definition & initialization can be (but not access beyond that).

  • Dear Great Teacher Mr. Alex and great supporter Mr/Mrs. nascardriver
      
    1) I tried to execute the above program in tutor 4.3 that have a function named incrementAndPrint(); with both static int s_value = 1;(declared as a local variable) and static int g_value = 1;(declared as a global variable ) and i recognized the  program executes  the same output.
    Depend on this fact are we able to conclude  that the effect of static key word  is the same in both local and global(Internal linkage) variable declaration? If we can't what are the reasons?  
    2) This program has also a variable s_value  with static duration and eventually  outputs 2,3 and 4.  Can you explain in more detail how it works? I have tried my best to know about it even by greeting  back to read  the previous sections.B/s i have seen that you are so busy with a lot of questions coming from others.  
    when the 1st incrementAndPrint(); function called it increment the value 1 to 2.what about the out put 3 (2nd function output) Does that mean the value of the first function would copied the value 2 to the secondly called function?
    Did we cover this idea in the previous chapter? where?
    God bless you all!!! You are changing my life indeed!!

    • 1) Static variables behave just like global variables, they're unique to the program.
      2)

      @s_value is only initialized one and maintains it's value across function calls.

      • Dear Mr/Mrs.nascardriver
        Thank you so much for your kind,prompt and clear response . Now i have gotten the point for static variables that they behave just like global variables except they have no linkage like global variables!!!
        And i like the way you clarify my number 2 question.

        I wish God be always with you all !!!
        Thank you indeed!

  • Nux

    Hello,

    I remember you was willing to change std::endl to "\n" in exemple

    The 2 first exemple here use std::endl

  • Hema

    Hello, I was experimenting with the calling functons. I wrote the following code. The compiler says: error:expected primary-expression before 'int'. The error is in line 11.
    Precisely here --> cout<<"x+y= "<< int x()+ int y()<<endl;
                                                            ^

    What does the compiler actually mean and how can I correct it?
    Thanks..

    • nascardriver

      Hi Hema!

      First, let's rename some variables to prevent duplicate names

      The error is still the same, let's look into it.
      You only need to specify the return and parameter types of a function when declaring it. Not when calling it. So when you want to call @x you don't write int.

      Now you're getting another error:

      When you declared @x you decided it should get a parameter (@i). When you call a function the requires parameters you need to pass them in the brackets.

      Your code now compiles and outputs

      Keep on experimenting, it's a good way to learn!

      • Hema

        Can I know why we shouldn't use "using namespace"? The program compiles fine with "using namespace" after removing "int" in line 11.  

        Thanks a lot for the help. :)

        • nascardriver

          'using namespace' can lead to naming conflicts. eg. The std namespace has a function called 'min'. This is quite a common name that could occur somewhere else too. You you were 'using namespace std' and called 'min' your compiler wouldn't be able to tell which 'min' you're trying to call.

          Reference
          Lesson 1.8a Naming conflicts and the std namespace

  • Trong Nguyen Van

    I see this is very nice. This static variable isn't destroyed after exiting its scope but we can only access to it in its scope again. In main() or other scope, we can't access it's value!

    Thank you!

  • Hema

    Can you eplain this sentence in more detail-"Static duration variables are only created (and initialized) once, and then they are persisted throughout the life of the program."
    Thanks

    • Alex

      Sure. Normally, if you have a variable defined inside a function (either as a parameter or local variable), that variable is created and destroyed every time the function is executed. There's no persistence. However, with a static variable, the static variable is only created the first time the function is run, and it is not destroyed when the function exits. The next time the function is run, the variable still exists and its previous value has been retained. The static variable is only destroyed at the end of the entire program.

  • felipe

    Is there a super static version of static(that makes the variable value persist even after the program is close?) thanks.

  • Kanwar Ujjwaldeep Singh

    VoidIncrementandPrint
    This Function has no return value,how it send's back value 2 bact to MAIN FUNCTION.
    When main function calls VoidIncrementandPrint, Value is created ,assigned value =1,than incremented and then destroyed at end.But its not sent back to the main Function.Than how it works>

Leave a Comment

Put all code inside code tags: [code]your code here[/code]