Should a const static variable be initialized in a c++ header file? - c++

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.

Related

Access static variable from CPP file to other header file

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

Should I put these functions in a standalone .h file?

I have a project which includes 2 files: main.cc and header1.h. While main.cc instantiates a class "className" and calls the member functions of it, the header file includes definition of the class.
main.cc:
#include <header1.h>
int main(){
className classobject();
classobject.function1();
...
}
}
header1.h:
class className{
public:
className();
void function1();
...
};
double className::function1(){
double function2(){
...
}
}
With this, I met an error which says:"a function definition should not be placed before '{' token.
So I decided to put the definition of function2 outside of the class, and put it in a standalone .h file. In that way, my project would include 3 files, namely: main.cc, head1.h and function2.h file:
main.cc:
#include <head1.h>
int main(){
className classobject;
void classobject.function1();
...
}
head1.h:
#include <function2.h>
class className{
double function2();
...
}
function2.h:
double function2(){
...
}
Although function2 can also be defined as the class member function so that it can be moved out of function1 while inside the class, I want to know whether the above mentioned treatment is leagal. Besides, does the creation of header files have some implicit rules established by usage (common treatment)?
Could anyone give some comments? Thanks in advance.
The first problem in your code that I see is that you define className::function1 in a header, but forgot to declare it inline. The outcome is that you can only use the header in a single compilation unit †. That's a bad design. I recommend defining it in a source file instead.
Secondly, you try to define function2 inside another function. That's not allowed and therefore you got a compilation error. You say that you decided to move it's definition outside the class, but it's definition was already outside the class definition. Moving the definition outside the definition of className::function1 is indeed a correct choice.
If function2 is reusable outside it's use in className::function1, then it's indeed a good idea and perfectly legal to declare it in a separate header. But just like className::function1, you're defining function2 also in the header again and again without declaring it inline and therefore you will get in trouble if you try to use it in multiple compilation units. I recommend defining function2 in a source file as well.
† If you include the header in multiple compilation units, then each of those compilation units will contain the definition of the function. The One Definition Rule does not allow defining a function in more than one compilation unit. Functions that are marked inline are treated differently. They may be defined in multiple compilation units as long as they have an identical definition in each.
Do something like this in your className.hpp
class className{
public:
className();
private:
void function1();
};
Then in your className.cpp
#include"className.hpp"
className::className(){ /*defintion*/ }
void className::function1(){ /*definition*/ }
Then you could use a makefile in oder to compute the className.o file and link it to the main file.
If you want to define another function (like function2()), you can then define it the className.cpp

Why I can implement the class's member function in header file?

I know that you should only declare a function in header and avoid define it because if more than one source file include this header ,the linker will tell you there are duplicate symbol.
I also know that it is recommended that declare a class in header and implement the member function in source file
But here is my question : I try to define the whole class in header (including all the implementation of member function) ,then I found that there was no error from linker when I include this header in two source files.
Here is my header.h file
class ctr
{
public:
ctr();
ctr(char *s);
int showname(){return 0;}
private:
char *name;
};
In other two file, I include header.h
//file1.cpp
#include header.h
//file2.cpp
#include header.h
Then compile them g++ file1.cpp file2.cpp
So can anyone tell me why normal function definition will give me an error but class definition is ok?
Member functions defined within the class body are implicitly inline [class.mfct]/p2:
A member function may be defined (8.4) in its class definition, in which case it is an inline member function [..]
The inline specifier allows a function to be defined across multiple translation units.

Why should I not initialize static variable in header? [duplicate]

This question already has answers here:
How to initialize private static members in C++?
(18 answers)
Closed 8 years ago.
So, let's say I have a header like this:
#ifndef BASECLASS_H
#define BASECLASS_H
class BaseClass
{
public:
static int getX(){return x;}
private:
static int x;
};
int BaseClass::x = 10;
#endif
I have heard many times that I should not initialise static variables inside a header, but rather in cpp. But as there are guards, there should be only one copy of BaseClass::x. So I kinda do not understand why I should put
int BaseClass::x = 10;
in cpp.
If you do it in the header, you'll get multiple definition errors as soon as you include it from more than one CPP file. You're really telling the compiler two things when you declare
int BaseClass::x = 10;
First, you're defining the symbol BaseClass::x; second you're telling it you want it to have the initial value of 10. According to the One Definition Rule this can only happen once in your program.
Maybe it's easier to understand if you think about what the preprocessor actually does: It copies the content of all included header files into the cpp file and passes this to the compiler.
Now let's say you have:
// In a.cpp
#include <baseclass.h>
// more code
// In b.cpp
#include <baseclass.h>
// more code
After the preprocessor expands the includes, both files will contain:
int BaseClass::x = 10;
Now as soon as both object files are passed to the linker, it will see the symbol BaseClass::x twice - which is an error.
Now, to make it even more obvious, imagine you would put this in a header file:
int aGlobalVariable = 10;
And then include it in two different cpp files, which should both be linked into one executable. It's actually not any different from your example, if seen from the linker's point of view.
Why is this not a problem with class declarations?
There's a difference between declarations and definitions. Only the latter will cause problems. E.g., all of the following are declarations:
extern int a;
void foo(int a);
class Foo { int bar(); };
Whereas these are definitions:
int a;
int b = 10;
void foo(int a) { /*..*/ }
int Foo::bar() { /*...*/ }
As long as there is one (and only one) definition, you can have as many declarations as you'd like, and the linker will make sure they all refer to the same function or memory location.
Now what about classes? Classes can only be declared, while their member functions and static members have to be defined. Again, each definition may only exist once.
Member functions and static members actually exist only once in a program's address space, whereas normal members (instance variables) exist for each object of the class.
Getting back to your specific problem: static members are basically just global variables, but scoped to the class' name.
Hope this clears things up for you!
The guards do not prevent multiple copies in multiple source files. They only prevent multiple copies in one source file.
You will be violating the one definition rule if you have multiple source files that #include "base_class.h".
Because If you initialize it in the header there is a possibility that it would be defined in multiple locations if you include the header more than once. Which will result in a linker error

No linker error when global variable declared static in the header file [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Static variables in C++
// x.h
int i = 3;
// x1.cpp
#include"x.h"
//...
// x2.cpp
#include"x.h"
//...
Above code will give linker error. However If I declare,
//x.h
static int i = 3;
It doesn't give linker error in gcc, even we have the same #include! Are we creating different static int i; for every .cpp file ? Will it cause any silent linking bug (due to same name)?
When C code is compiled, it's one "translation unit" at a time. Early on, #includes are expanded into the text of the referenced files. So what you've got in the static case is equivalent to x1.cpp saying static int i = 3; and x2.cpp doing the same. And static in this context means roughly "don't share this with other translation units."
So yes, when you use static there you are making two different i variables which have nothing to do with each other. This will not cause a linking error.
int x; is a definition of the entity x. The One Definition Rule of C++ says that any variable that is used shall be defined exactly once in the program. Hence the error.
static says that x has internal linkage. That is, the x's that appear in one.cpp and two.cpp are two different unrelated entities.
The C++ standard says that the use of static in this case is deprecated(As per Steve's comment, in C++0x it's undeprecated). Anonymous namespaces provide a superior alternative.
namespace
{
int x;
}
Also note that unlike C, in C++ const variables of scalar types also have internal linkage. That is
const int x = 7; // won't give you an error if included in different source files.
HTH
Are we creating different static int i; for every .cpp file ?
Yes
Will it cause any silent linking bug (due to same name)?
No. Due to static, they have different names.
If this isn't the behavior you want, you need to use extern in the header file, and allocate the variable in one translation unit (.cpp file)
static creates a global variable that is only visible inside the unit.
If you want to use a variable in more than on ecompilation unit, use extern in the header and declare it in the implmenetation without extern.
You get the linker error in your first code example because i is defined and exported in both compilation units. In the second case i is static, so there is no exported symbol because static variables are only visible in the current compilation unit and aren't exported to the linker. In this case you have two independent variables that are both called i.
As written, the code looks like the same i is being accessed by multiple .cpp files, whereas in reality, each .cpp file will have its own copy. This can lead to misunderstandings and bugs.
If you want there to be just one copy of i, the preferred idiom is to wrap it in an accessor function in x.h:
int& GetI() {
static int i = 3; // this initialization only happens once.
return i;
}
If you do want separate copies of i for each .cpp file, a much clearer expression of this is to simply declare i separately in each .cpp file:
namespace {
int i;
}
Putting it in an anonymous namespace as above keeps it from being accessible from other .cpp files, for safety.