2

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
2
  • 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. Commented Aug 7, 2019 at 5:30
  • @NikosC. this is the answer that made me understand why it won't define in the header, thanks! Commented Aug 8, 2019 at 2:13

3 Answers 3

6

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.
};
Sign up to request clarification or add additional context in comments.

1 Comment

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. godbolt.org/z/h_-HAg
5

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.

1 Comment

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. godbolt.org/z/h_-HAg
-1

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!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.