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

102 comments to 8.11 — Static member variables

  • Micah

    Why does it print backwards if you don't initialize a new std::cout call?
    output for this is:
    0
    1
    3 2

    • Hi Micah!

      The evaluation order of multiple << is undefined.

      • Micah

        Thanks, I see, then different statements guarantee evaluation order.
        Okay then a couple questions if you don't mind..
        If they are undefined in evaluation order, why do they evaluate backwards? Does the computer just have to assume how to print and evaluate with the operator? And if so, why does it assume the same way each time?
        Would that not be an update-able fix to reverse the process?
        And, is there another way to send multiple calls like this to the console on one line? Or is this just a qwerk of C++?

        • The compiler decides the evaluation order. Yours appears to evaluate the statement backwards. As long as you're using the same compiler, you'll get the same results.

          > Would that not be an update-able fix to reverse the process?
          Reversing the order is probably easy, but the c++ standard doesn't state a specific order, so there is no reason to choose one way over the other.

          > is there another way to send multiple calls like this to the console on one line?
          Store the values in temporaries before printing them

          The behavior of this code is the same across all compilers.

  • Aditi

    Thank you for the great examples . They were really easy to understand and explained the concept very well 🙂

  • Dr. Khalid Alharbi

    Hi Alex,

    I think static member definition and initialization is not subject to access controls,but static members that are under private section cannot be accessed directly using the class name or through objects of the class. We need to use static member functions to access (i.e., read and/or write) static data members.
    The following code works fine, but if you try to run the comments you will receive an error: ‘int Something::s_value’ is private within this context.

    [code]
    #include <iostream>
    using namespace std;
    class Something
    {
         public:
         Something()
         {
             setvalue();
            
         }
         static int getvalue()
         {
             return s_value;
         }
         static void setvalue()
         {
              ++s_value;
         }
          private:
          static int s_value;
    };

    int Something::s_value=0 ;

    int main()
    {
        Something first;
        Something second;

        //first.s_value = 2;
       // cout << first.s_value << '\n';
       //cout << second.s_value << '\n';
       //cout << Something::s_value << '\n';
       cout << Something::getvalue() << '\n';
        return 0;
    }
    [code]

  • 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]