Thread: Why initialization of static member is a must?

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    284

    Why initialization of static member is a must?

    Here is a simple example:

    Code:
    struct E{
    public:
    	static int c;
    	E() {c++;}
    	~E(){c--;}
    };
    
    //int E::c=0;
    int main(){
    	E e;
    	return 0;
    }
    We can see if we declare c as "int c" rather than "static int c", it can compile. When c is declared as "static int c", it can't compile without "int E::c=0;". Why is that?

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Because the declaration "static int c" just says that somewhere else, there shall be a definition of E::c. It does not cause the definition by itself.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    284
    Then why int c works? Why complier does not force it to be defined?

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    int c; means that each instance of class E has a variable named c (which it is then up to the constructor, presumably, to deal with). static int c; means that there is a variable which belongs to the class as a whole, and must therefore be defined once, somewhere, for the class.

  5. #5
    Registered User
    Join Date
    Jan 2007
    Posts
    330
    because static class members are shared over all classes and they may only have 1 instance in the entire program. Its up to the programmer where to define this variable.
    "normal" member variables get a new instance whenever an object of the class is created

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The initialization is not necessary, though, only the definition is. In other words
    int E::c;
    is enough (and c will still be 0).
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Is there a reason why the compiler can't do that itself without you explicitly declaring it (other than if you want it initialized to something other than default)?

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, the reason is that the compiler can't really know WHERE to place this "autogenerated" variable. Note that:
    Code:
    int x;
    int E::c;
    int y;
    will ensure that x and y are either side of E::c in memory.

    Since it's essentially a global variable, you may want to put it somewhere it makes sense to sit [e.g. together with other variables that are used together with it, for caching benefits]

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by meili100 View Post
    Then why int c works? Why complier does not force it to be defined?
    Because each object contains its own non-static variable, there is no logical place where such a definition could be placed. Therefore, for non-static members, the declaration serves as the definition for all instances.

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by matsp View Post
    Note that:
    Code:
    int x;
    int E::c;
    int y;
    will ensure that x and y are either side of E::c in memory.
    Not true. Order or location of declarations of variables does not control where they are physically placed in memory. Some compilers might elect to do such things, but there is no guarantee they will.

    To answer the original question, declarations of non-static members of a class are actually a definition (so, whenever an instance of the class is created, its non-static members are). For static members of a class, the declaration within the class body is not a definition. ie in your example, "static int c;" is the declaration and "int E::c = 0;" is the definition.

    Why is all this tap-dancing necessary? Given two (or more) source files in which the compiler sees
    Code:
    struct E{
    public:
    	static int c;
    };
    the compiler and linker, as a pair, could theoretically infer that one definition of E::c is needed and resolve any usage of that static member in those multiple source files so, in effect, E::c is defined exactly once.

    The problem is, with separate compilation of source files, the compiler cannot resolve such things in isolation -- such resolutions require examination of all the source files as a set. The typical dumb linker (the program that links object files and libraries together to create an executable entity, which is what is supplied with most operating systems and/or development environments) also tends to choke if more than one definition occurs across multiple object files and libraries. The common practical situation, therefore, is a compiler that can't resolve the concern without help and a dumb linker that won't help it. That puts the onus back onto the programmer to explicitly resolve the issue and ensure only one definition occurs across all source files. This sort of thing is the basis for the "One Definition Rule" (ODR) in the standard. [There's more justification for the ODR than that, but that's the basic idea.]

    Smarter linkers (that do analysis across multiple object files to resolve situations of multiple definitions and other phenomena) do exist, but they are rare. With a smarter linker the definition "int E::c;" would actually be optional.

    The net effect of all that is that the standard must allow for the full range of practical situations, and a common practical situation involves usage of dumb linkers. So, practically;
    1) "static int c;" within struct E is treated by typical compilers as a declaration (the standard treats it that way too);
    2) the subsequent "int E::c;" is treated as a definition.
    3) the linker must see exactly one definition (otherwise it will emit an error message about multiply definitions)
    Last edited by grumpy; 04-11-2008 at 05:25 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. const correctness and static member variables
    By cunnus88 in forum C++ Programming
    Replies: 2
    Last Post: 02-21-2008, 05:26 PM
  2. get keyboard and mouse events
    By ratte in forum Linux Programming
    Replies: 10
    Last Post: 11-17-2007, 05:42 PM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. Static member of a class
    By Gravedigga in forum C++ Programming
    Replies: 2
    Last Post: 08-15-2005, 03:54 AM
  5. illegal references in static member functions
    By bennyandthejets in forum Windows Programming
    Replies: 10
    Last Post: 12-31-2002, 10:11 AM