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 variables 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:


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:


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 safer for use even if you change their values regularly.

Best practice

Initialize your static local variables. Static local variables are only initialized the first time the code is executed, not on subsequent calls.

Static local constants

Static local variables can be made const. One good use for a const static local variable is when you have a function that needs to use a const value, but creating or initializing the object is expensive (e.g. you need to read the value from a database). If you used a normal local variable, the variable would be created and initialized every time the function was executed. With a const static local variable, you can create and initialize the expensive object once, and then reuse it whenever the function is called.

Don’t use static local variables to alter flow

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:

Enter an integer: 5
Enter another integer: 9
5 + 9 = 14
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

Enter an integer: 5
Enter another integer: 9
5 + 9 = 14
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 s_isFirstCall) which cannot be reset from the outside. s_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 s_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 in 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.

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
6.9 -- Sharing global constants across multiple files (using inline variables)

160 comments to 6.10 — Static local variables

  • Jordan

    I kind of confuse, why wont it return 1 when it first returned? Why isn't it returned the incremented value of 0 which is 1.

    • Alex

      Postfix++ (where the ++ is after the variable) returns the number prior to it being incremented. Prefix++ (where the ++ is before the variable) increments the numbers and then returns the number after it has been incremented.

  • Forhad Rahman

    "because cats are cool"
    - This made my day LMAO!

  • Alsctiho

    if I have a function's parameter is a static local variable, like

    And I call this function twice with different arguements.

    Will the s_local be initialized once and ignore the second call? Or s_local will be created twice, and the second one will shadow the first one?

  • J G

    Can someone explain the difference between constexpr and const? I've tried reading multiple explanations on it, but still don't get it.

    • SuperNoob

      This is broadly described in previous chapters. You missed maybe.

      • J G

        And you might've missed the part where I say I've read multiple explanations and still don't get it. Curb the attitude.

        • Alex

          A constexpr constant must be given a value that is known at compile time.
          A const constant may be given a value that is known at compile time (in which case it is treated as constexpr) or runtime

          For example:
          constexpr int x { 5 }; // the value of x is known at compile time, so this is okay
          const int y { 2 + 3 }; // the value of y is known at compile time, so this const will actually be treated as constexpr
          void someFcn(const int z); // the value of z isn't known until runtime, so this is normal runtime const
          void someFcn(constexpr int w); // the value of w isn't known until runtime, so this is a compile error

          There are some things that can only be done with constexpr values.

    • hektik

      Main difference is const variables are defined at programs run-time, or execution, and constexpr variables are defined during compilation of the code

    • Lesommeil

      Const variable can use to array declaration, so isn't the same during compilation? Because I think runtime is after link-time.

  • Cliff

    Hi and first thanks. Second, is your discussion on the pitfalls of static local variables (which create state) related to 'pure' functions? It seems that any function with state can't be pure.

    • nascardriver

      Hi, yes. Pure functions are good. Functions with `static` local variables aren't pure. Thus functions with `static` local variables aren't as good as functions without `static` local variables.

  • hi

    Just a few typos:

    In the first sentence of "Static local variables", "variable" should be "variables".

    In that same section, within the sentence after the "2 3 4", "Just like we use" should be "Just like we used".

    Toward the end, in the last sentence before "Best practice", "and if the foreseeable future" should be "and in the foreseeable future".


    • nascardriver

      "Just like we use" is correct, because it's still something we do, it's not in the past.
      I fixed the other 2 typos, thanks for pointing them out!

  • Jorge Mouta

    should be

    to enforce best pratices.

  • sam

    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).

    i have  two questions
    1- Is a constant expression here means  compile-time constants and literals only  ?
    examples (consider the variables within functions
    example 1:
    static int s_value = 5;

    example 2:
    constexpr int x = 5;
    static int s_value = x;

    2 - is a normal variable with literal intializer considered a constant expression ?
    example :
    int x = 5;
    static int s_value = x;

    or runtime constants are constants expressions
    example :
    const int x = add(3,5);
    static int s_value = x;

    • nascardriver

      1- compile-time expression

      2- No. You'd have to make `x` `const` or `constexpr` to count as a constant expression.

      If you want to check if something counts as a constant expression, try using it to initialize a `constexpr` variable

  • Joe Jiao

    Hi, I have trouble understanding the following sentence:
    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).
    If you zero-initialize a variable then initialize it with supplied value, isn't  that just reinitialization?

  • Fan

    I come up with a use of static local variables which I am not sure is good practice or not.

    Suppose I have a function f() that needs an unspecified amount of scratch space to compute some value. Let's say the scratch space is obtained by creating an std::vector<int>. I can create it as an automatic local variable. Every time the control enters f(), an std::vector<int> of certain size is allocated, and every time f() exits, it's deallocated. But dynamic memory allocation has some cost. I want to avoid that, so can I create the std::vector<int> as a static local variable? This way if the next time I call f() I don't use as much space as last time, there is no reallocation of the space, so it serves as some kind of "memory pooling". Is it a good idea?

    • nascardriver

      If the function is only used from 1 thread, you can do it like that. To make it more portable, you could let the caller pass in the vector and if the caller wants to apply your optimization, they can make the vector static.

Leave a Comment

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