#044 – When to use static local variables

A local variable has local scope. It’s duration is linked to the function it’s defined in. Mark it static and the rules change: the variable persists for the entire program, but its name remains scoped to the function.

This article will explore this useful combination of static duration and internal linkage with 2 examples.

A Refresher

Consider the following

#include <iostream>

void print() {
    int y{19}; // x has automatic duration
    std::cout << x++ << '\\n';
} // x gets destroyed after the function returns

int main() {

    print();
    print();
    print();
}

// Terminal
19
19
19

Hmm, that’s not what we’re looking for.

If we want the value to persist across function calls, we can assign static to the local variable.

#include <iostream>

void print() {
    static int y{19}; // Apply static. x acquires static duration
    std::cout << x++ << '\\n';
}

int main() {

    print();
    print();
    print();
}

// Terminal
19
20
21

Now the variable increments as expected. When the function returns, it doesn’t destroy y.

An application

Have a variable remember its value across numerous function calls is very useful.

This property can be used to build a unique ID generator program.

#include <iostream>

int generateID() {
    static int s_id{ 0 };
    return s_id++;
}

int main() {
    constexpr int total_users{ 12 };
    for (int i = 0; i < total_users; ++i) {
        std::cout << "Your unique ID is: " << generateID() << '\\n';
    }
}

// terminal
Your unique ID is: 0
Your unique ID is: 1
Your unique ID is: 2
Your unique ID is: 3
Your unique ID is: 4
Your unique ID is: 5
Your unique ID is: 6
Your unique ID is: 7
Your unique ID is: 8
Your unique ID is: 9
Your unique ID is: 10
Your unique ID is: 11

One-time initialization

The initialiser of a static local runs exactly once, on the first call. Thus, it’s paired with the Singleton pattern. Since C++11, this is guaranteed to be thread-safe.

EventBus& EventBus::Instance() {
    static EventBus instance;
    return instance;
}