I'm trying to access the static variable in other header file from a CPP file.
"Boo.hpp"
#ifndef Boo_hpp
#define Boo_hpp
static int num;
class Boo
{
public:
Boo()
{
num = 35;
}
};
#endif /* Boo_hpp */
"Foo.hpp"
#ifndef Foo_hpp
#define Foo_hpp
class Foo
{
public:
Foo();
};
#endif /* Foo_hpp */
"Foo.cpp"
#include "Foo.hpp"
#include "Boo.hpp"
#include <iostream>
Foo::Foo()
{
std::cout << "Num : " << num << '\n';
}
"main.cpp"
#include <iostream>
#include "Foo.hpp"
#include "Boo.hpp"
int main()
{
Boo boo;
Foo foo;
}
The Result I get :
Num : 0
Program ended with exit code: 0
The Result I expect :
Num : 35
Program ended with exit code: 0
If I move the class Foo's constructor implementation from Foo.cpp to Foo.hpp, my code works as expected.
However, I would like to be able to access the num from Foo.cpp.
How should I fix my code?
All translation units which includes the Boo.hpp will have their own definition of the num variable. No other TU (Translation Unit) will have the same num variable.
That's what the static linkage storage modifier means (for non-local, non-member variables).
You need to understand two things to understand what is happening here.
In C++, header files are just text which is "copy-pasted" to each .cpp file which includes them, directly or indirectly. The resulting preprosessed source code is "compilation unit", so you can basically think one .cpp file is one compilation unit.
static global variables (not to be confused with static member variables of classes, AKA class variables, which are essentially same as non-static global variables...) are visible inside the compilation unit they are defined in. If you define static global variable in two compilation units, they are completely independent variables, and do not interfere (their names are not visible outside the compilation unit either). So, unless you know you do want separate copy of the variable in multiple .cpp files (very rare), you shouldn't put static global variables in .h file (extern declaration of global variable defined in a .cpp file is what you usually want in a .h file).
Now when you combine these two things, you realize that the static variable defined in .h file is no different from static variable defined in .cpp file. If .h file is included in several .cpp files, you get several copies of the variable, and which one is being used depends on which .cpp file it is (directly or through includes).
You have two .cpp files, which both define same static variable here, so they have two copies, and code compiled in these will use different variables.
Now there is extra quirk here. If you define a member function, including the constructor, inline (happens implicitly when you define it inside a class, if you define it in .h file but outside class you have to use the inline keyword), then every .cpp file will get a different copy of that function. Now you as programmer promise they will be the same, that is what inline means (it has only a little to do with inline optimization). If you have several copies of the same constructor (defined in a .h file), and they actually access different static variable, then they are not the same, and you break the promise. Don't do that!
The keyword static on globals in C/C++ instructs the compiler to limit that symbol to the current compilation unit, i.e. the file it's declared in. Putting static declarations into header files is a huge trap because even though you include the same header in all your source files, each file will receive its own copy of the static symbol.
What you want is the extern keyword, that declares the symbol to be shared between compilation units, i.e. extern int num.
Some more reading on storage class specifiers here
Related
I was reading about inline functions and how they could have multiple definitions in different Translation Units but those definitions must be the same.
So what I was thinking is that if I declared in a header file a function and define it in 2 cpp files as inline the compiler will not be angry.
So I tried to do as follow :
global.h
#ifndef DRAKOS_GLOBAL_H
#define DRAKOS_GLOBAL_H
#include <iostream>
void fct();
#endif //DRAKOS_GLOBAL_H
file1.cpp
#include "global.h"
inline void fct()
{
std::cout << "file1.cpp \n";
}
main.cpp
#include "global.h"
extern void fct();
int main()
{
fct();
}
Builging ---> Error :
undefined reference to `fct()'
Ok I looked around in google and I read that
It’s imperative that the function’s definition be placed in a header
file, unless the function is used only in a single .cpp file.
Till now all clear and logic, but the question is, if I put the definition in the header file; every TU will have the same definition, I won't be able to define two versions of the inlined function say one in the file1.cpp TU and the second in the main.cpp TU.
So question 1 : why they say, that for an inline function, could have mutliple definitions in different TU but must be the same (as if I put the definition in the header it will be and couldn't do different in cpp file)
question 2 : If It is possible to do so and define multiple definitions of an inled function (due to miss understanding from my side) could somone plz show me an easy example :)
Thanks in advance
This code causes undefined behaviour (no diagnostic required) due to rule C++17 [dcl.inline]/6:
[...] If a function or variable with external linkage is declared inline in one translation unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required.
You have fct declared inline in file1.cpp but not in main.cpp.
Also you do not have any definition for fct in main.cpp. You could copy and paste into main.cpp (and every other .cpp in the project):
inline void fct()
{
std::cout << "file1.cpp \n";
}
But that would be bad practice because it would be easier to accidentally change one of the functions or forget about a .cpp file. Having it in a header file avoids this problem.
I am using forward declaration, and I have already been careful not to have any definition inside header files (only declaration), and also have #pragma once directive before each header file. Yet somehow multiple definition error is still happening. So in GlobalSys.h, I use forward declaration, then i will include this file to any file that needs access to this global variable. In application.h, i initialize this global variable so I have to include EventManager.h or the compiler will complain. Where am I doing wrong?
GlobalSys.h
#pragma once
class EventManager;
namespace GlobalSys {
EventManager * eventManager;
}
Application.h
#include "GlobalSys.h"
#include "../Event/EventManager.h"
class Application {
public:
Application();
};
Application.cpp
#include "Application.h"
Application::Application() {
GlobalSys::eventManager = new EventManager();
}
and I have already been careful not to have any definition inside header files (only declaration)
No, you defined GlobalSys::eventManager in GlobalSys.h.
Definitions are declarations that fully define the entity introduced by the declaration. Every declaration is a definition, except for the following:
Any declaration with an extern storage class specifier or with a language linkage specifier (such as extern "C") without an initializer
You can change it to declaration with using of extern.
GlobalSys.h
#pragma once
class EventManager;
namespace GlobalSys {
extern EventManager * eventManager; // declaration
}
then define it in another implementation file, e.g.
GlobalSys.cpp
#include "GlobalSys.h"
namespace GlobalSys {
EventManager * eventManager; // definition
}
once (and other include guards) won't prevent multiple definitions. once prevents a header from being included twice by a single cpp file (translation unit). If multiple translation units include the same header, they will all have their own copy of everything in that header. That includes defined variables and functions. All these translation units are compiled separately, so any one run of the compiler doesn't know that another run already included the header and produced an object file that has its own copy of the same stuff.
The Linker, however, has to take these multiple translation units and put them together into a single program. And it finds all of the duplication. Rather than try to sort out what the programmer really wants, it gives up and asks the programmer to clarify.
Songyuanyao's answer provides one solution for this problem: Declare the variable with extern instead of defining it in the header, and then define the variable in a single translation unit. This allows multiple translation units to share a single variable. You can do the same with a function definition with the inline keyword.
Sometimes, but not this time, you want every translation unit to have their own variable. In that case
#pragma once
class EventManager;
namespace GlobalSys {
namespace {
EventManager * eventManager;
}
}
The anonymous namespace restricts eventManager's linkage to a single translation unit so each translation unit's eventManager do not conflict.
my_test.h
#ifndef MY_TEST
#define MY_TEST
struct obj {
int x;
int y;
};
class A {
private:
const static int a=100;
const static obj b;
};
const obj A::b={1,2};
#endif
When compiling cpp using this header file, an error 'multiple definition of 'A::b' occurs.
why is this when I have been using guard macro already?
why does A::a not produce the erro? (I can't write code const static obj b={1,2} in class A)
why is this when I have been using guard macro already?
Header guards only prevent the inclusion of the header file contents more than once in the same translation unit not across multiple translation units.
why is A::a does not have the error message (I can't write code const static obj b={1,2} in class A)
In-class initialization is allowed by the compiler as a special case for static data members of const literal type. Your example one is In-class initialization.
const A::b defines the same symbol name in each translation unit where the header gets included and hence breaks the one definition rule.
You need to move the definition to one and only one source cpp file so that it gets defined only once.
Alok has already answered your question, but here are a few simple rules of thumb, in easy-to-memorize form:
Declarations go in the .h file
Definitions go in the .cpp file
Therefore, static members need to be declared in the .h file, and then defined in the .cpp file. In your case, fix the syntax for the declarations and then move them to "my_test.cpp" file.
The problem is your definition of A::b doesn't contain a type. To be a valid definition, it should be:
const obj A::b = {1, 2};
This will get rid of the compilation error, but you'll still get linker errors if you include this header in more than one source file, because A::b will be multiply defined then. You should move the definition into a .cpp file.
Regardless of whether you have a header guard or not, placing that initialisation in a header file will mean you'll get an instance of A::b in every source file that includes that header file. Hence the linker error.
So, generally speaking, it's possible, but not a good idea.
If you want to put function definitions in header files, it appears there are three different solutions:
mark the function as inline
mark the function as static
put the function in an anonymous namespace
(Until recently, I wasn't even aware of #1.) So what are the differences to these solutions, and when I should I prefer which? I'm in header-only world, so I really need the definitions in the header files.
The static and unnamed namespace versions end up being the same: each Translation Unit will contain it's own version of the function, and that means that given a static function f, the pointer &f will be different in each translation unit, and the program will contain N different versions of f (more code in the binary).
This is not the right approach to provide a function in a header, it will provide N different (exactly equal) functions. If the function contains static locals then there will be N different static local variables...
EDIT: To make this more explicit: if what you want is to provide the definition of a function in a header without breaking the One Definition Rule, the right approach is to make the function inline.
As far as I know, only inline and template functions can be defined in header files.
static functions are deprecated, and functions defined in an unnamed namespace should be used instead (see 7.3.1.1 p2). When you define a function in an unnamed namespace in a header, then every source code including that header (directly or indirectly) will have an unique definition (see 7.3.1.1 p1). Therefore, functions should not be defined in the unnamed namespace in header files (only in source files).
The standard referenced are from the c++03 standard.
EDIT:
Next example demonstrates why functions and variables shouldn't be defined into unnamed namespace in headers :
ops.hpp contains:
#ifndef OPS_HPP
#define OPS_HPP
namespace
{
int a;
}
#endif
dk1.hpp contains:
#ifndef DK1_HPP
#define DK1_HPP
void setValue();
void printValue();
#endif
dk1.cpp contains:
#include "dk1.hpp"
#include "ops.hpp"
#include <iostream>
void setValue()
{
a=5;
}
void printValue()
{
std::cout<<a<<std::endl;
}
dk.cpp contains :
#include "dk1.hpp"
#include "ops.hpp"
#include <iostream>
int main()
{
// set and print a
setValue();
printValue();
// set and print it again
a = 22;
std::cout<<a<<std::endl;
// print it again
printValue();
}
Compile like this:
g++ -ansi -pedantic -Wall -Wextra dk.cpp dk1.cpp
and the output :
5
22
5
ops the variable a is different for the source file dk1.cpp and dk.cpp
static functions (equivalent to anonymous namespace) receive different copies for each TU. If the function is re-entrant this is basically identical (some compilers might have assembly-level differences) but if it isn't then it will have different static data for each TU. Inline functions are folded- that is, they have only one copy of static data for every TU.
You could consider wrapping the methods in a class instead of a namespace. Declare these methods as static and delete the constructor of the class to reinforce that this is not an object to be instantiated.
struct FooNamespace
{
FooNamespace() = delete;
static FooMethod1() {
...
}
static FooMethod2() {
...
}
};
You get the same general behavior as it belonging to a namespace with only a single implementation.
In the header I declared
#ifndef SOUND_CORE
#define SOUND_CORE
static SoundEngine soundEngine;
...
but the constructor for SoundEngine gets called multiple times, how is it possible, when it's declared as global static
I call it as
#include "SoundCore.h"
and use it directly
soundEngine.foo()
thank you
I would use extern instead of static. That's what extern is for.
In the header:
extern SoundEngine soundEngine;
In an accompanying source file:
SoundEngine soundEngine;
This will create one translation unit with the instance, and including the header will allow you to use it everywhere in your code.
// A.cpp
#include <iostream>
// other includes here
...
extern int hours; // this is declared globally in B.cpp
int foo()
{
hours = 1;
}
// B.cpp
#include <iostream>
// other includes here
...
int hours; // here we declare the object WITHOUT extern
extern void foo(); // extern is optional on this line
int main()
{
foo();
}
A copy of static variables declared in header files gets created for each translation unit where you include the header.
Never declare your static variables inside header files.
You could use a singleton object.
As others mentioned in the answers, static variable in header file gets included in every file where the the header is included. If you want to still keep it static and avoid multiple instantiations then wrap it in a struct.
//SoundCore.h
struct Wrap {
static SoundEngine soundEngine;
};
Now define this variable in one of the .cpp files.
//SoundCore.cpp
SoundEngine Wrap::soundEngine;
And use it simply as,
Wrap::soundEngine.foo();
If you include this header file in multiple files, your class will be instantiated for every inclusion. I think you better take a look at Singleton pattern, to get only 1 instance, i.e., just one constructor call.
As many other reserved words, static is a modifier that has different meanings according with the context.
In this case, you are creating an object of the class SoundEngine which is private in this module. This means that it is not visible from other modules.
However, you put this line in the header, so it is a private object in various modules. I guess that's the reason of the constructor being called multiple times.