Show Lecture.LocalStatic as a slide show.
CS253 Local Static
Try #1
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. Of course, id
got re-initialized
every time that next_id()
was called.
Try #2
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
Better, but now we have an evil global variable.
👹
Try #3
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
Better in that id
is only visible to this file,
but that’s still semi-global. Can we improve?
Try #4
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.
👏
Summary
- A variable has two aspects, scope (spatial) and
lifetime (temporal).
- scope : visibility; which code can access the variable
- lifetime : duration; when the variable is
created & destroyed
- static can change either of these.
- It changes the scope of a global variable to be only the current
file.
- It changes the lifetime of a local variable so that it’s
initialized only once, and persists until program end.
It’d be nice to have separate words for those distinct purposes, but
standards committees are stingy with new words, and re-use old ones.
static global example
// Remember program starting time:
static const auto start = time(nullptr);
int main() {
cout << start << '\n';
sleep(1);
cout << start << '\n';
}
1732257253
1732257253
- A static global:
- is visible only in that source file (scope)
- is created/initialized at program start (lifetime), like any global
- is destroyed at program end (lifetime), like any global.
Actually, in the global scope, const implies static,
so the above definition is a bit redundant.
Home Directories
- Every user has a home directory.
It’s where you are when you log in.
- On some systems, it’s always
/home/username
. Not here!
- cs253’s home directory is
/s/bach/a/class/cs253
.
- ’s home directory is
.
- In a shell, but not in a program, tilde (
~
) represents my home
directory, and ~user
means somebody else’s home directory.
- In the I/O Streams lecture, we used
getpwnam() to translate a user name into a struct that
holds the home directory path.
- getpwnam() can be slow—on our systems, it consults a central
password database over the network.
- So, we’d like to minimize how many times we call getpwnam().
static local example
string homedir() {
// Call expensive getpwnam() once, at most.
// Segfault if the lookup fails! 😧
static string d = getpwnam("cs253")->pw_dir;
return d;
}
int main() {
cout << homedir() << '\n'; // first is slow
cout << homedir() << '\n'; // second is fast
}
/s/bach/a/class/cs253
/s/bach/a/class/cs253
- A static local:
- is visible only in that function (scope)
- is created upon first use—when the function
is first called (lifetime)
- is destroyed at program end (lifetime).
Example
char foo() {
static char id = 'A';
cout << "foo: returning " << id << "\n";
return id++;
}
static 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