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;
}