Here’s a program to generate unique student ID numbers:
unsigned long next_id() { unsigned long id=800000000UL; return ++id; } int main() { cout << next_id() << '\n'; cout << next_id() << '\n'; cout << next_id() << '\n'; }
800000001 800000001 800000001
That wasn’t very good.
Let’s move id
out of next_id()
:
unsigned long id=800000000UL; unsigned long next_id() { return ++id; } int main() { cout << next_id() << '\n'; cout << next_id() << '\n'; cout << next_id() << '\n'; }
800000001 800000002 800000003
That’s better, but now we have an evil global variable.
Let’s make id
static
:
static unsigned long id=800000000UL; unsigned long next_id() { return ++id; } int main() { cout << next_id() << '\n'; cout << next_id() << '\n'; cout << next_id() << '\n'; }
800000001 800000002 800000003
That’s better in that id
is only visible to this file,
but that’s still semi-global. Can we do better?
Move id
back to next_id()
, but leave it static
.
unsigned long next_id() { static unsigned long id=800000000UL; return ++id; } int main() { cout << next_id() << '\n'; cout << next_id() << '\n'; cout << next_id() << '\n'; }
800000001 800000002 800000003
Hooray! Now, id
is private and persistent.
A variable has two aspects, scope and lifetime.
scope: determines which code can access the variable
lifetime: determines when the variable is created, and when it’s destroyed
static
changes both of these. It changes the scope of a global
variable to be only the current file. It also changes the lifetime
of the variable so that it is initialized only once, and persists until
the program ends.
A static
global is initialized at program start.
A static
local is initialized upon first use—when the function
is first called.
char foo() { static char id = 'A'; cout << "foo: returning " << id << "\n"; return id++; } auto glob = foo(); int main() { cout << "glob = " << glob << '\n'; for (int i=0; i<5; i++) { if (i>10) { static char zip = foo(); cout << "zip = " << zip << '\n'; } static char bar = foo(); cout << "bar = " << bar << '\n'; } return 0; }
foo: returning A glob = A foo: returning B bar = B bar = B bar = B bar = B bar = B