3.10. Static functions and variables¶
By default, all functions are global;
they can be used in any file of your program whether or not a declaration appears in a header file.
To limit access to the
current file, declare a function or variable static
, like this:
// assume all these definitions are in a single file "foo.cpp"
// static variable used by non-static functions
static bool verbose = false;
bool is_verbose() {
return verbose;
}
// vprint could reside in another file
void vprint (std::string message) {
if (is_verbose()) {
std::cout << message << '\n';
}
}
// this function only works if it is the same file
// as the one where verbose is defined
void verbose_print (std::string message) {
if (verbose) {
std::cout << message << '\n';
}
}
// local static function can only be called in this compilation unit
static void helloHelper(void) {
puts("hi!");
}
// anyone can call `hello`
void hello(int repetitions) {
for(int i = 0; i < repetitions; ++i) {
helloHelper();
}
}
Similar to file static functions and variables,
the keyword static
can also be used inside functions.
Static variables are initialized only the first time the function is called,
for example:
size_t counter() {
static size_t count = 0;
return ++count;
}
The first time counter
is called,
the variable count
is initialized to zero.
Each call thereafter, count
is increased by 1 and the new value is returned.
Another appropriate use of static variable in functions:
when defining a constant that should only be initialized once.
For example, our earlier too_small
function, could be:
#include "area.h"
bool too_small (int x, int y) {
static const int min_size = 10;
return area(x, y) < min_size;
}
Under very rare circumstances, it may be useful to have a variable local to a function that persists from one function call to the next. You can do so by declaring the variable static. For example, here is a function that counts how many times it has been called:
// return the number of times the function has been called
int counter(void) {
static count = 0;
return ++count;
}
Static local variables are stored in the same memory space as global variables. But they are only visible inside the function that declares them. This makes them slightly less troublesome than global variables; there is no fear that some unrelated code elsewhere will quietly change their value. Static variables are rarely used in practice, however, because they do not work well in multi-threaded applications.
3.10.1. Anonymous namespaces¶
It is possible to define a namespace without a name. Unnamed namespace members have potential scope from their point of declaration to the end of the translation unit.
In other words, they behave a bit like global variables, visible to all functions, but only within the source file where the namespace is defined.
Unnamed (or anonymous) namespaces are considered a ‘modern’
C++ alternative to declaring variables as static
within a translation unit.
static int i;
// anonymous namespace
namespace {
int i;
}
At one point the C++ standards committee planned to deprecate the use
of static
in this way and force the use of namespaces,
but that decision was reversed in 2009.
Unnamed namespaces are preferred over the use of the keyword static for several reasons:
The
static
keyword can have different meanings depending on contextNamespaces only have one purpose: to define and enclose a scope.
Namespaces provide a uniform and consistent way of controlling visibility. You don’t have to use different tools for the same thing.
A namespace can encapsulate anything. Only functions and objects can be declared static.
User defined types, which is the focus of the second half of this course cannot be declared static.
// valid statements static void my_function() { /* function body */ } static int my_variable; // invalid static class sample_class { /* class body */ }; static struct sample_struct { /* struct body */ }; // valid namespace { class sample_class { /* class body */ }; struct sample_struct { /* struct body */ }; }
When using an anonymous namespace, the function/object name is mangled properly, which allows you to see something like “(unique namespace)::xyz” in the symbol table after de-mangling, and not just “xyz” with static linkage.
At compile time, This definition is treated as a definition of a namespace with a unique name and a using-directive in the current scope.
namespace {
int i; // defines ::(unique)::i
}
The unique name of the namespace is hidden. Since it is not known, no code outside the current translation unit can access it.
It is technically possible to have more than one unnamed namespace in the same translation unit.
namespace {
int i; // defines ::(unique)::i
}
namespace A {
namespace {
// reusing the name 'i' in this scope is a bad idea . . .
int i; // A::(unique)::i
int j; // A::(unique)::j
}
void g() { i++; } // A::unique::i++
}
As a best practice, you should keep unnamed namespaces to a minumum and declare them near the top of your translation unit so that they stand out.
More to Explore
From: cppreference.com: