Navigation



8.11 — Static member variables

Static keyword in C

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:

int GenerateID()
{
    static int s_nID = 0;
    return s_nID++;
}

int main()
{
    std::cout << GenerateID() << std::endl;
    std::cout << GenerateID() << std::endl;
    std::cout << GenerateID() << std::endl;
    return 0;
}

This program prints:

0
1
2

Note that s_nID has kept it’s value across multiple function calls.

The static keyword has another meaning when applied to global variables — it changes them from global scope to file scope. Because global variables are typically avoided by competent programmers, and file scope variables are just global variables limited to a single file, the static keyword is typically not used in this capacity.

Static member variables

C++ introduces two new uses for the static keyword when applied to classes: static member variables, and static member classes. Before we go into the static keyword as applied to member variables, first consider the following class:

class Something
{
private:
    int m_nValue;
public:
    Something() { m_nValue = 0; }
};

int main()
{
    Something cFirst;
    Something cSecond;
    return 0;
}

When we instantiate a class object, each object gets it’s 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_nValue — one inside cFirst, and one inside cSecond. cFirst->m_nValue is different than cSecond->m_nValue.

Member variables of a class can be made static by using the static keyword. Static member variables only exist once in a program regardless of how many class objects are defined! One way to think about it is that all objects of a class share the static variables. Consider the following program:

class Something
{
public:
    static int s_nValue;
};

int Something::s_nValue = 1;

int main()
{
    Something cFirst;
    cFirst.s_nValue = 2;

    Something cSecond;
    std::cout << cSecond.s_nValue;

    return 0;
}

This program produces the following output:

2

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

Although you can access static members through objects of the class type, this is somewhat misleading. cFirst.s_nValue implies that s_nValue belongs to cFirst, and this is really not the case. s_nValue does not belong to any object. In fact, s_nValue exists even if there are no objects of the class have been instantiated!

Consequently, it is better to think of static members as belonging to the class itself, not the objects of the class. Because s_nValue exists independently of any class objects, it can be accessed directly using the class name and the scope operator:

class Something
{
public:
    static int s_nValue;
};

int Something::s_nValue = 1;

int main()
{
    Something::s_nValue = 2;
    std::cout << Something::s_nValue;
    return 0;
}

In the above snippet, s_nValue 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_nValue. This is the preferred method for accessing static members.

Initializing static member variables

Because static member variables are not part of the individual objects, you must explicitly define the static member if you want to initialize it to a non-zero value. The following line in the above example initializes the static member to 1:

int Something::s_nValue = 1;

This initializer should be placed in the code file for the class (eg. Something.cpp). In the absense of an initializing line, C++ will initialize the value to 0.

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:

class Something
{
private:
    static int s_nIDGenerator;
    int m_nID;
public:
    Something() { m_nID = s_nIDGenerator++; }

    int GetID() const { return m_nID; }
};

int Something::s_nIDGenerator = 1;

int main()
{
    Something cFirst;
    Something cSecond;
    Something cThird;

    using namespace std;
    cout << cFirst.GetID() << endl;
    cout << cSecond.GetID() << endl;
    cout << cThird.GetID() << endl;
    return 0;
}

This program prints:

1
2
3

Because s_nIDGenerator is shared by all Something objects, when a new Something object is created, it’s constructor grabs the current value out of s_nIDGenerator and then increments the value for the next object. This guarantees that each 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 (eg. to look up the name of something, or to find a pre-calculated value). By making the lookup table static, only one copy exists for all objects, rather than 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

42 comments to 8.11 — Static member variables

    • ZNorQ

      Alex,

      First off; great site! I’ve tried figuring out C++ for a long time, and this is the site that managed to give me extensive and logical explanations to the C++ confusion. You’ve made C++ my primary choice!

      Anyway, in your text under the “Static member variables” heading you state the following;
      “C++ introduces two new uses for the static keyword when applied to classes: static member variables, and static member classes.”

      Shouldn’t it say “and static member functions” instead of “classes”?

      Kenneth aka ZNorQ.

  • Renu

    static int s_nValue; ……
    int Something::s_nValue = 1;

    Why is “int” used in initialising
    Something::s_nValue = 1

    We have already declared s_nValue as static int in class definition. What is the purpose of using
    int again in
    ” int Something::s_nValue = 1; ” ?

    Thanks,
    Renu

    • This is a good question, and I am not sure of the answer. Because static members belong to the class, not objects of the class, I presume the declaration in the class is essentially treated as a forward declaration of the static member, which is actually defined in the body of the code. Thus, much like forward declarations for functions, which need to have the return type and parameter types in both the forward declaration and the actual definition, this would adhere to the same rules.

      • Dayu

        I tried the third code without the line

         int Something::s_nValue=1;

        . i.e.

        #include <iostream>
        class Something
        {
        public:
            static int s_nValue;
        };
        
        //int Something::s_nValue;
        
        int main()
        {
            Something cFirst;
        
            Something cSecond;
            std::cout << cSecond.s_nValue;
        
            return 0;
        }
        

        I got a compilation error:

        …/main.cpp|15|undefined reference to `Something::s_nValue’|.

        I also tried

         int Something::s_nValue;

        Note that there is no “=1″ this time, and everything works out fine with s_nValue=0;
        Does this mean

         int Something::s_nValue;

        is always needed when we declare a static variable of a class? By the way, I am using Code::Blocks with GCC as the compiler on my Ubuntu.

  • Zafer

    Two questions. In the last coding example, why didn’t we declare the objects cFirst, cSecond and cThird as const objects since we are using the GetId function, which has const in its declaration? My second question is about the static keyword. In the explanation provided after the last example, it says: “This guarantees that each Something object receives a unique id (incremented in the order of creation).” However since there is only one copy of the static variable and as we increment it, the id values of cFirst, cSecond and cThird will all be the same instead of being unique. This part needs to be clarified.

    • cFirst, cSecond, and cThird could be declared as const objects since they only call GetID(), which is const.

      The basic idea here is that there is only one copy of s_nIDGenerator that is shared amongst all of the objects of type Something. However, each individual object has it’s own m_nID value that is not shared.

      When we construct a new Something, the Something constructor copies the current value of s_nIDGenerator into the not-shared m_nID and then increments it. Keep in mind that when we increment s_nIDGenerator, this does not affect any of the m_nID values that have already been assigned!

      So let’s look at what happens in more detail. First, s_nIDGenerator is set to 1.

      At this point we have:
      s_nIDGenerator = 1

      Then, we construct cFirst. cFirst’s constructor copies the value of s_nIDGenerator (1) into cFirst.m_nID and then increments s_nIDGenerator to 2.

      At this point we have:
      cFirst.m_nID = 1
      s_nIDGenerator = 2

      Then, we construct cSecond. cSecond’s constructor copies the value of s_nIDGenerator (2) into cSecond.m_nID, and then increments s_nIDGenerator to 3.

      At this point we have:
      cFirst.m_nID = 1
      cSecond.m_nID = 2
      s_nIDGenerator = 3

      Finally, we construct cThird. This proceeds in the same way as the previous constructors.

      At this point we have:
      cFirst.m_nID = 1
      cSecond.m_nID = 2
      cThird.m_nID = 3
      s_nIDGenerator = 4

      Note that s_nIDGenerator is not used any more. It is only used to set the initial value of m_nID. If we ask a Something object for it’s ID, it always returns it’s non-shared m_nID value.

  • [...] 2007 Prev/Next Posts « 8.9 — Class code and header files | Home | 8.11 — Static member variables » Tuesday, September 11th, 2007 at 6:19 [...]

  • davidv

    I have 2 questions.
    First: in the last example, s_nIDGenerator was declared as a private member, but was accessed outside the class. I compiled the code, and it works. How come we didn’t run into trouble?
    Second: the name convention for static member does not reflect membership. Wouldn’t something like ms_nName be better than s_nName?
    Thank you.

    • luke

      First: This is from Schildt’s “The Complete Reference: C++ 4th ed.”
      When you declare a static data me3mber within a class, you are not defining it. (That is, you are not allocating storage for it.) Instead, you must provide a global definition for it elsewhere, outside the class.
      You’re not accessing a private variable, but rather defining it. This also sheds some (more) light on Renu’s question.

      Second: Are you serious? I’m pretty sure Alex put the ‘s’ and ‘m’ prefixes there to distinguish between static and member. ‘s’ is definitely easier to distinguish from ‘m’ than “ms”. Let’s not forget these are examples. I’m surprised you didn’t comment on “Something” not being a very good class name.

  • cammy

    In your first example how could GenerateID() evaluate to 0 if s_nID is set to 0 but then incremented before the end of the function? Should it not print the following

    1
    2
    3
    • The function returns s_nID++; This means the value of s_nID is set aside, then s_nID is incremented, then the old value of s_nID is returned.

      For example, let’s say s_nID is 0. The value 0 is copied into a temp variable. s_nID is incremented to 1. Then the value 0 is returned.

      All of this happens transparently when you use the postfix ++ operator. That’s why using the prefix ++ operator can be more efficient.

  • Zelbacsi

    I’m so confused right now …

    In 4.2 you said not to use global variables:

    “2) To hold data that needs to be used by the entire program (eg. configuration settings).”
    (that’s what i’d need to do)

    “there are better ways to do #2 (eg. static classes).”
    Still, I didn’t found anything like “static classes” in later lessons. Did you mean this? (classes with static members) Although, from your examples, ‘static’ seems to serve an entirely different purpose in classes, then the one mentioned above in 2)

  • baldo

    Alex, I think you made a typo here: “C++ introduces two new uses for the static keyword when applied to classes: static member variables, and static member classes.” I think it is static member functions not classes.

  • heya

    small typo:
    In fact, s_nValue exists even if there are no objects of the class have been instantiated!
    should be
    In fact, s_nValue exists even if no objects of the class have been instantiated!

    or, you know, something similar. Nice website, I’ve learnt more here than in my university. They insist on “taking it slow” by teaching nothing more complex than pointers. You know, really incredibly abstract things like object oriented programming that only gurus and wise old men can know. I’m lucky they aren’t trying to ease me into c by teaching me pascal first (they did that up to this year).

  • srikanth

    i have a small question is static variable can be used in defining singleton of a class more efficently

  • Dawid Chemloul

    I have questions and maybe some answers.

    1. Is static in function variable guaranteed to be initialized (created) at first function call or is it compiler dependent?

    as for singletons – it is possible to use static member to create singleton with nice encapsulation but I would rather use static variable in function if answer for my first question is yes.

    Since if you will try make some static singleton objects – or some static objects using your singletons then initialisation order of all those global static globals need to be maintained with care.

    Since it is possible that you will create a singleton instance before global member was initialised – then initialisation of global member will override previous usage… this seamnot to pose problems used this way in VS2010

    Example:

    class Singleton
    {
    public:
      static Singleton & getInstance()
      {
         static Singleton *instance = 0;
         if( ! instance )
         {
            instance = new Singleton();
         }
         return *instance;
      }
    };
    
  • Dawid Chemloul

    – edit deleted

  • Poke

    Hello! I’m having an issue with a static member variable…my g++ compiler is giving me the error: undefined reference to `ShipType::m_format’. Nearly all of the comments I’ve read say to instantiate the static outside the class, which I have done. Here’s my code snippet:

    //ShipType.h
    class ShipType
    {
    public:
    	enum Type {null, DD, SS, CA, BB, CV};
    	enum Format {abbreviated, verbose};
    ...
    	static string toString(ShipType::Type);
    ...
    protected:
    	static ShipType::Format m_format;
    };
    
    //ShipType.cpp
    #include "ShipType.h"
    ...
    ShipType::Format m_format = ShipType::verbose; //Here's where I've instantiated the static
    
    string ShipType::toString(ShipType::Type t)
    {
    ...
      if (ShipType::abbreviated == ShipType::m_format) //error message applies to this LOC
        retVal = shipStringsA[t];
      else
        retVal = shipStringsV[t];
      return retVal;
    )//toString
    

    Thank you in advance…

    Poke

    • D.M. Ryan

      Did you try changing

      static ShipType::Format m_format;

      to

      static Format m_format;

      ?

      In the examples above, the class scope isn’t added when a static variable is declared within the class itself.

      That fix may not work, but it’s worth a try.

      ShipType::Format m_format = ShipType::verbose;

      is correct.

  • abbas

    hey alex i have to questions
    Q1:what means about “hidden argument to the function” using this pointer.
    Q2: what means “function is called for an object”.

  • Ashish79

    Hi,
    Can we call non-static functions with static objects?

  • [...] Static variable member class Share this:TwitterFacebookLike this:LikeBe the first to like this post. This entry was posted in Uncategorized. Bookmark the permalink. ← May I have your address? [...]

  • [...] ‘s’ is common in the C++ literature (for example, it is used in the Learncpp.com lesson on static member variables). In this way, mValue would be a non-static member variable of a class, whereas sValue would be a [...]

  • [...] should not actually exist, which leads me to believe that this is a quirk of Visual Studio 2010. According to learncpp, “In the absense of an initializing line, C++ will initialize the value to [...]

  • [...] 8.11 — Static member variables « Learn C++ Because static member variables are not part of the individual objects, you must explicitly define the static member if you want to initialize it to a non-zero value. The following line in the above example initializes the static member to 1: [...]

  • bobt

    “Because static member variables are not part of the individual objects, you must explicitly define the static member if you want to initialize it to a non-zero value.”

    It seems like this is incorrect. As many (including yourself) have pointed out if you comment out the definition then you will get a linker error. I suggest this wording instead:

    “Because static member variables are not part of the individual objects, you must always explicitly define the static member.”

  • ashly

    like static member variables , static member functions , is static class itself possible in c++?

  • [...] can't be initialized inside a function. I was confused when I did my recent review on C++ from here. The example is showing showing the assignment in purple within the main() function. But what I [...]

  • [...] static class variable and functions Share this:TwitterFacebookLike this:Like Loading… July 20, 2013 Leave a reply [...]

  • [...] the previous lesson on static member variables, you learned that classes can have member variables that are shared across all objects of that [...]

  • [...] new subject matter of scope,  static variables, references to variables and the const key word are covered in more detail in these [...]

  • Chris_M

    Alex,

    In the last paragraph of this section, you mention an internal lookup table. Are there any examples on this site on how to implement an internal lookup table? Thank you.

You must be logged in to post a comment.