1

I always struggle to discover why I'm getting "Undefined reference to static variable" in my code, and I always end up in these questions:

Undefined reference to static variable c++

Undefined reference to static variable

I understand that I need to define my data outside the class declaration.

In the example:

class Helloworld {
  public:
     static int x;
     void foo();
};

int Helloworld::x = 0; // Or whatever is the most appropriate value
                       // for initializing x. Notice, that the
                       // initializer is not required: if absent,
                       // x will be zero-initialized.

I must initiate x to some value. But what about static members that are class instances? Why simply the compiler won't make an instance for me with the default constructor?

If I write

class A {
    public: 
        B b;
}

then I can do

A a;
a.b;

I don't need to define B b outside the A class declaration. Why do I need to do it for the static example below?

class A {
    public: 
        static B b;
}

B A::b
Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • 4
    "*Why simply the compiler won't make an instance for me with the default constructor?*" Where should it do that? If it does, then every file that includes the header is going to make an instance. So you will have several instances. That's why you need to tell it where to define it (meaning in which cpp file.) C++17 introduces `inline` to allow multiple definitions in every cpp file, but in the end keep only one of them. – Nikos C. Aug 07 '19 at 05:30
  • @NikosC. this is the answer that made me understand why it won't define in the header, thanks! – Guerlando OCs Aug 08 '19 at 02:13

3 Answers3

4

Static members exist before any object is created, that is what makes them static. Therefore their initialization does not happen on first instance, they are there already.

They are actually global variables within a class scope.

That said, you can use the inline modifier to initialize them inside the class without an out of class declaration.

Info here and here.

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • Do note that `inline` variables come at a small cost: initialization becomes more complex, because initialization order needs to be guaranteed top to bottom for a single translation unit, and `inline` variables are in multiple translation units. https://godbolt.org/z/h_-HAg – Justin Aug 07 '19 at 06:24
4

But what about static members that are class instances? Why simply the compiler won't make an instance for me with the default constructor?

But make it where? The rational for this prior to C++17 was that there must be only one such definition of the static member under the one definition rule. So it was up to the programmer to specify exactly in which translation unit that definition should live, even if the object was to undergo default initialization. The compiler wasn't trusted to "do the right thing"TM.

As compilers got smarter, and C++17 came about, it turned out that compilers really can be made to figure it out. In C++17 you can specify the static member as an inline variable, and the compiler/linker will sort it out.

class A {
    public: 
        static inline B b; // There, an inline variable default initialized.
};
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    Do note that `inline` variables come at a small cost: initialization becomes more complex, because initialization order needs to be guaranteed top to bottom for a single translation unit, and `inline` variables are in multiple translation units. https://godbolt.org/z/h_-HAg – Justin Aug 07 '19 at 06:21
0

You need to define B outside the class for the same reason you have to define x outside the class: because it’s a static member. Being a primitive type (int) or class type (B) has nothing to do with it!

Pedro LM
  • 742
  • 4
  • 12