Search

8.11 — Static member variables

Review of static keyword uses

In the lesson on file scope and the static keyword, you learned that static variables keep their values and are not destroyed even after they go out of scope. For example:

This program prints:

1
2
3

Note that s_id has kept its value across multiple function calls.

The static keyword has another meaning when applied to global variables -- it gives them internal linkage (which restricts them from being seen/used outside of the file they are defined in). Because global variables are typically avoided, the static keyword is not often used in this capacity.

Static member variables

C++ introduces two more uses for the static keyword when applied to classes: static member variables, and static member functions. Fortunately, these uses are fairly straightforward. We’ll talk about static member variables in this lesson, and static member functions in the next.

Before we go into the static keyword as applied to member variables, first consider the following class:

When we instantiate a class object, each object gets its own copy of all normal member variables. In this case, because we have declared two Something class objects, we end up with two copies of m_value: first.m_value, and second.m_value. first.m_value is distinct from second.m_value. Consequently, the program above prints:

2
1

Member variables of a class can be made static by using the static keyword. Unlike normal member variables, static member variables are shared by all objects of the class. Consider the following program, similar to the above:

This program produces the following output:

2
2

Because s_value is a static member variable, s_value is shared between all objects of the class. Consequently, first.s_value is the same variable as second.s_value. The above program shows that the value we set using first can be accessed using second!

Static members are not associated with class objects

Although you can access static members through objects of the class (as shown with first.s_value and second.s_value in the example above), it turns out that static members exist even if no objects of the class have been instantiated! Much like global variables, they are created when the program starts, and destroyed when the program ends.

Consequently, it is better to think of static members as belonging to the class itself, not to the objects of the class. Because s_value exists independently of any class objects, it can be accessed directly using the class name and the scope resolution operator (in this case, Something::s_value):

In the above snippet, s_value is referenced by class name rather than through an object. Note that we have not even instantiated an object of type Something, but we are still able to access and use Something::s_value. This is the preferred method for accessing static members.

Defining and initializing static member variables

When we declare a static member variable inside a class, we’re telling the compiler about the existence of a static member variable, but not actually defining it (much like a forward declaration). Because static member variables are not part of the individual class objects (they are treated similarly to global variables, and get initialized when the program starts), you must explicitly define the static member outside of the class, in the global scope.

In the example above, we do so via this line:

This line serves two purposes: it instantiates the static member variable (just like a global variable), and optionally initializes it. In this case, we’re providing the initialization value 1. If no initializer is provided, C++ initializes the value to 0.

Note that this static member definition is not subject to access controls: you can define and initialize the value even if it’s declared as private (or protected) in the class.

If the class is defined in a .h file, the static member definition is usually placed in the associated code file for the class (e.g. Something.cpp). If the class is defined in a .cpp file, the static member definition is usually placed directly underneath the class. Do not put the static member definition in a header file (much like a global variable, if that header file gets included more than once, you’ll end up with multiple definitions, which will cause a compile error).

Inline initialization of static member variables

There are a few shortcuts to the above. First, when the static member is a const integral type (which includes char and bool) or a const enum, the static member can be initialized inside the class definition:

In the above example, because the static member variable is a const int, no explicit definition line is needed.

Second, as of C++11, static constexpr members of any type that supports constexpr initialization can be initialized inside the class definition:

An example of static member variables

Why use static variables inside classes? One great example is to assign a unique ID to every instance of the class. Here’s an example of that:

This program prints:

1
2
3

Because s_idGenerator is shared by all Something objects, when a new Something object is created, the constructor grabs the current value out of s_idGenerator and then increments the value for the next object. This guarantees that each instantiated Something object receives a unique id (incremented in the order of creation). This can really help when debugging multiple items in an array, as it provides a way to tell multiple objects of the same class type apart!

Static member variables can also be useful when the class needs to utilize an internal lookup table (e.g. an array used to store a set of pre-calculated values). By making the lookup table static, only one copy exists for all objects, rather than making a copy for each object instantiated. This can save substantial amounts of memory.

8.12 -- Static member functions
Index
8.10 -- Const class objects and member functions

96 comments to 8.11 — Static member variables

  • Peter Baum

    The static member definition and initialization looks just like a global to me in terms of where it is defined and its function.  The only thing slightly different is that it is namespace qualified by the class name.  Is there anything else that differentiates it from an ordinary global?

  • April

    How is it that the first, second, and third objects can access the getId member function if it is const and the objects themselves are not?

    • nascardriver

      Hi April!

      Non-const objects can access const-functions (The object is allowed to be modified, the function doesn't modify anything, everything is fine).
      Const objects can't access non-const functions (The object is not allowed to be modified, the function wants to modify the object, not allowed).

  • Arnav Borborah

    You have written:

    "Second, as of C++11, static constexpr members of any type can be initialized inside the class definition:"

    Does this apply for classes without constexpr constructors? How would they be initialized at compile time? (I presume they won't since classes such as std::vector use runtime dynamic allocation)

    • nascardriver

      Hi Arnav!

      I'm not sure if I got your question right since what you wrote isn't related to your quote.

      The quote states that this is allowed

      What (I think) you asked is having a constexpr object of a type without a constexpr constructor

    • Alex

      constexpr variables aren't initialized at compile time (they are initialized at run-time). However, the value they are initialized with must be known at compile time.

      C++ doesn't currently support const (or constexpr) constructors in any case.

      • Arnav Borborah

        Alex, C++ actually [does support `constexpr` constructors](http://en.cppreference.com/w/cpp/language/constexpr). (Scroll down a bit to see it).

        nascardriver, I'm asking that if I am allowed to do:

        When CNonConst does NOT have a constexpr constructor. I am confused about why it says "any type" when this is not allowed for classes without a constexpr constructor.

        • Alex

          1) I stand corrected!
          2) I see what you're getting at. I'll amend the text to be more specific that this applies only to types that can actually be created as constexpr.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]