2.9. The Keyword static

[ fromfile: statics.xml id: statics ]

The keyword static can be applied to local variables, class members, and global variables/functions. In each case, static means something different.

static Local Variables

The keyword static can be applied to a local variable declaration to give the variable static storage class (Section 20.3).

A local static variable is created only once and initialized the first time its declaration statement is processed by the running program. It is destroyed when the program terminates. A nonlocal static is created once, when the object module is loaded into memory, and is destroyed when the program terminates.

static Class Members

A static data member is a piece of data associated with the class itself rather than one that belongs to a particular object. It does not affect the sizeof() an object of the class. Each object of a class maintains its own set of non-static data members, but there is only one instance of any static data member, and it is shared by all objects of the class.

static members are preferable to (and can generally replace the use of) global variables because they do not add unnecessary names to the global namespace.

[Note] Global Namespace Pollution

Adding names to the the global scope (e.g., by declaring global variables or global functions) is called global namespace pollution and is regarded as bad programming style. There are many good reasons to avoid declaring global variables in your programs. One is that it increases the likelihood of name collisions and confusion. Some experts use the number of global names in a program as an inverse measure of the program's quality (the lower the number, the higher the quality).

static class members must be declared static in (and only in) the class definition.

Example 2.9. src/statics/static.h

[ . . . . ]
class Thing {
public:
    Thing(int a, int b);
    ~Thing();
    void display() const ;
    static void showCount();
private:
    int m_First, m_Second;
    static int s_Count;
};
[ . . . . ]

Figure 2.3 shows a UML class diagram for class Thing from Example 2.9.

Figure 2.3.  UML Class Definition with static

UML Class Definition with static

Notice that the static members are underlined in the diagram.

A class member function that does not in any way access the non-static data members of the class can (and should) be declared static. In Example 2.9, the static data member is a private counter that keeps track of the number of Thing objects that exist at any given moment. The public static member function displays the current value of the static counter.

Each static data member must be initialized (defined) once outside the class definition, preferably in the corresponding class implementation file. [28] Example 2.10 shows how to initialize and use static members.

Example 2.10. src/statics/static.cpp

#include "static.h"
#include <iostream>

int Thing::s_Count = 0;        1

Thing::Thing(int a, int b)
        : m_First(a), m_Second(b) {
    ++s_Count;
}

Thing::~Thing() {
    --s_Count;
}

void Thing::display() const {
    using namespace std;
    cout << m_First << "$$" << m_Second;
}

void Thing::showCount() {      2
    using namespace std;
    cout << "Count = " << s_Count << endl;
}

1

Must initialize static member!

2

Static function.


[Note] Note

Notice that the term static does not appear in the definitions of s_Count or showCount(). For the definition of s_Count, the keyword static would mean something quite different: It would change the scope of the variable from global to file-scope (see Section 20.2). For the function definition, it is simply redundant.

Block-scope Static

statics defined inside a function or a block of code are initialized when they are executed for the first time.

long nextNumber() {
    int localvar(24);
    static long statNum = 1000;
    cout << statNum + localvar;
    return ++statNum;
}

The first call to nextNumber() initializes localvar to 24 and statNum to 1000, displays 1024 on the screen, and returns 1001. When the function returns, localvar is destroyed but statNum is not. Each time that this function is called, localvar gets created and initialized to 24 again. The static variable statNum persists between calls and holds onto the value that it obtained in the last call. So, for example, the next time the function is called, 1025 is displayed and 1002 is returned.

static Initialization

A static object that is not defined in a block or function is initialized when its corresponding object module[29] is loaded for the first time. Most of the time, this is at program startup, before main() starts. The order in which modules get loaded and variables get initialized is implementation-dependent, so you should never make an initialization depend on the initial value of a static from a different file, even if you list that file first when compiling.

A static object is constructed once and persists until the program terminates. A static data member is a static object that has class scope.

In Example 2.11, we make use of an internal block so that we can introduce some local objects that will be destroyed before the program ends.

Example 2.11. src/statics/static-test.cpp

#include "static.h"

int main() {
    Thing::showCount();     1
    Thing t1(3,4), t2(5,6);
    t1.showCount();         2
    {                       3
        Thing t3(7,8), t4(9,10);
        Thing::showCount(); 4 
    }                       5

    Thing::showCount(); 
    return 0;
}

1

At this point, no objects exist, but all class statics have been initialized.

2

Access through object.

3

An inner block of code is entered.

4

Access through class scope resolution operator.

5

End inner block.


Here is the compile and run.

src/statics> g++ -Wall static.cpp static-test.cpp
src/statics> ./a.out
Count = 0
Count = 2
Count = 4
Count = 2
src/statics>



[28] The exception to this rule is a static const int, which can be initialized in the class definition.

[29] Chapter 7, "Libraries and Design Patterns"