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 context

    Namespaces 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.


You have attempted of activities on this page