Initializing variables in header C++

12,686

Solution 1

Aside from the obvious incorrect naming (which I assume was simply a matter of hastily creating an analogous example and is not the actual issue in your code), you need to declare the variable as extern in your .h/.hpp file. You cannot have an extern variable that is also static since the (one of the) use(s) of static is to keep the variable contained to within a single .cpp file.

If you change:

static int testNumber = 10;

in your A.h file to:

extern int testNumber;

and then in your A.cpp file do something like:

#include "A.h"
int testNumber = 10;

Now go ahead and run:

int main() {
    //changeNumber();
    std::cout << testNumber << std::endl; // prints 10
    changeTestNumber(); // changes to 15
    std::cout << testNumber << std::endl; // prints 15
    std::cin.ignore();
    return 0;
}

Be sure to fix the function names!

Solution 2

Goodies and others are certainly correct, but let me put one more step ahead:

  1. static makes the definition local to the translation unit. So defining a static global variable in the header will result in as many copies as the translation units it is included. Unless that's not specifically what you want that's not the way

  2. extern tells the compiler that the global variable exist somewhere, but is not defined and must be searched at link phase. To the linker to succeed, you need to define it somewhere (typically a source file where it make more sense to exist)

  3. Omitting both of them will result in a "multiple definition" linker error, where more than one source includes an header.

Now, the 2nd case has two limitation:

  • it forces you to have a compilable source to instantiate a global object even in the case you are providing a template library (or an "header only" library) making delivery more complex as required
  • It exposes to the so called global initialization fiasco: if you initialize a global object with values taken from other global objects defined elsewhere, since C++ doesn't grant about their order of construction (that ultimately belongs to the way the linker works), you may have trouble in proper initialization and destruction of global objects.

To avoid all this, consider that

  • A global defined function, if explicitly declared as inline can be linked more times and
  • Template functions as well as in-class defined member functions are in-lined by default
  • static local object are created only once, the first time they are encountered

You can define global values in headers by making them static local to functions: like in

inline int& global_val() //note the &
{ static int z = 0; return z; }

the only drawback is that you have always to place a () upon every access.

Since the local value is unique and instantiated upon a call, this will ensure that, if there are dependencies between globals (think to int z=0 as int z=something_else()) they will be created in the order they are needed and destroyed in reverse order, even in case of recursion and multiple threads (since c++14)

Considering the evolution of C++ towards generics and functional paradigms, and considering that placing all sources in a single compilation unit is sometime preferable than linking many sources... Have a think about not using global variables, but replacing them with inlined instatiator functions.


Editing about 2 years later:

C++17 have finally introduced the inline directive for also for variable declarations, just as a syntactic shortcut to the function expansion.

So -today- you can simply write

inline const float PI = 3.14159;
inline int goodies = 25;

Solution 3

A.h

extern int testNumber;
void changeNumber();

A.cpp

#include "A.h"

int testNumber = 10;

void changeTestNumber()
{
    testNumber = 15;
} 

B.h

#include "A.h"
// some other stuff

B.cpp

#include "B.h"
// some other stuff

main.cpp

#include "B.h"
#include <iostream>

int main(){

    changeTestNumber();
    std::cout<<testNumber<<std::endl;

    return 0;

}

Please try like that.

Share:
12,686
remi
Author by

remi

Mechanical Engineer; hobby programmer.

Updated on June 04, 2022

Comments

  • remi
    remi almost 2 years

    EDIT: correct function names, and added #pragma once

    This is a very strong simplification of my problem, but if I do this:

    A.h

    #pragma once
    static int testNumber = 10;
    void changeTestNumber();
    

    A.cpp

    #pragma once
    #include "A.h"
    
    void changeTestNumber()
    {
        testNumber = 15;
    } 
    

    B.h

    #pragma once
    #include "A.h"
    // some other stuff
    

    B.cpp

    #pragma once
    #include "B.h"
    // some other stuff
    

    main.cpp

    #pragma once
    #include "B.h"
    #include <iostream>
    
    int main(){
    
    changeTestNumber();
    std::cout<<testNumber<<std::endl;
    
    return 0;
    }
    

    Why am I not getting testNumber = 15 at the call out? What really happens when I use a function that is included in a header of my included header? If I remove the static in from of int testNumber, I will get some error about my testNumber being initialized twice.

    So is my header compiled twice when I do this?

    Thanks in advance!