Static variables and different namespaces in c++ - c++

I have read on static variables and know what they are, how they function when define in a .cpp file, function, and class.
But I have slight confusion when define in different namespaces in the same cpp file.
One of these voted answers here says:
When you declare a variable as static inside a .h file (within or without namespace; doesn't matter), and include that header file in various .cpp files, the static variable becomes locally scoped to each of the .cpp files.
According to the program below, namespaces does matter.
static int a = 0;
namespace hello1 {
static int a = 1;
namespace hello2 { static int a = 2;}
namespace hello3 { static int a = 3;}
}
int main()
{
std::cout<<::a<<hello1::a<<hello1::hello2::a<<hello1::hello3::a;
return 0;
}
output
0123
Here is what I think: a outside namespaces is the file scope. a in hello1 is hello1 scope. Since hello1 is global scope namespace, I can only have one a in namespace hello1, including other cpp files where hello1 exists. The same goes for hello2 and hello3; only one a in each hello1::hello2 and hello1::hello3.
Please correct me If I understood it correct. The namespace does matter; static variables in the same cpp file under different namespaces are different entities.

That's not what the passage you quoted is talking about. It is referring to the fact that static variable names have internal-linkage. What that means is that you can't access a static variable a that is defined in "a.cpp" from "b.cpp", even if you include a declaration of a in "b.cpp". That declaration will refer to a different object.
For example:
A.hpp
static int a = 0;
void foo();
A.cpp
#include "A.hpp"
#include <iostream>
void foo() { std::cout << a << '\n'; }
B.cpp
#include "A.hpp"
#include <iostream>
int main() {
std::cout << a << '\n'; // prints 0
a = 1;
foo(); // prints 0, since it uses a different a
}
In this example, "A.cpp" and "B.cpp" see different global-scope objects named a since a was declared static. Even though main modifies a's value to be 1, foo still sees it as 0 since it's looking at a different a.
This behavior is irrespective of namespaces. If a were in a namespace other than the global namespace this same behavior would occur. That is what the passage you quoted is referring to.

Related

Correct way of initializing a class globally in C++

I know global is bad but just as a practice, is this the correct way to initialize a global class used between multiple object files?
Header 1.h
class test {
int id;
public:
test(int in){
id = in;
}
int getId(){
return id;
}
};
extern test t;
File 1.cc:
#include <iostream>
#include "1.h"
int main(){
std::cout << t.getId() << std::endl;
return 0;
}
File 2.cc:
#include "1.h"
test t(5);
Now what if instead of extern I use the static approach globally static test t(0); in the header?
Correct me if I'm wrong but that would compile fine however I would have 2 different unrelated copies of the same t in both object files and the final binary? Is that bad? Or does the linker sort it out to eliminate multiple copies?
There are global instances, not global classes.
What you have is a global instance. And yes, this sounds about right, until you get to multiple global instances which depend upon each other. Then the real fun will start.
Defining a variable as 'static' at global level means the variable will be defined in the compilation unit only (i.e. the '.o' file) and the symbol won't be exported by the compiler.
In other words: yes, there will be multiple variables with the same name but only visible to functions on the same compilation unit.
Besides, 'invisible' doesn't mean 'inaccessible'. You still can provide access to the variable. For example:
1.h
struct Test { int value; }; // Class definition
Test& get_t(); // Function declaration
1.cc
#include "1.h"
static Test t; // Variable declared as 'static'
Test& get_t() { return t; };
2.cc
#include "1.h"
#include <iostream>
int main()
{
std::cout << get_t().value << std::endl; // Static variable accessed
}
I use the static approach globally static test t;?
But your test class needs an int in parameter for the constructor, so you want:
static test t(0); // or whatever int you want
If you turn the extern to static in the header, you would define a static variable in each compilation unit in which the header is imported. So classes in different cpp files would no longer "communicate" via t, since each would have theirs. This is very error prone.
In addition, adding the definition of a static in a header is an extremely bad practice. When someone includes a header, one does not expect that it will create variables.
Including the declaration of t as extern is an acceptable practice. But be aware that if the header has a general purpose, this might reduce its reusability other projects.
More information of interest for you:
Must read: C++ Core Guidelines about source files
Must read: Guidelines for writing headers
StackOverflow: When are global variables recommended
Why global variables should be avoided if possible and when are they ok
If you put a variable declaration outside of any function, you're declaring the variable as 'global'. Ex:
1.cc
int this_is_global;
From here on you can use the variable in any function of '1.cc'.
For using the same variable in any other file, the compiler will need to know about it:
2.cc
extern int this_is_global;
Here, the keyword extern tells the compiler that the variable is declare somewhere else, letting the task of finding it to the linker.
If you miss to add the extern keyword here, the compiler will treat it as a new variable, and the linker will have two variables with the same name and will emit an error. All of your source files of your project except the first one will need the extern keyword to avoid duplicate symbols.
So common practice is to add the 'extern' declaration in an include file:
1.cc
int this_is_global;
1.h
extern int this_is_global;
2.cc
#include "1.h"
On the other side, the static keyword tells the compiler not to export the symbol. In other words: the variable will exists only in the source file it is declared. You could declare it once per source file and there will be different variables with the same name. Ex:
1.h
static int my_var;
1.cc
#include "1.h"
2.cc
#include "1.h"
This way, you'll end having two variables 'my_var' and changes to any of them won't affect the other.

Static Global Variable Not Shared Between Threads [duplicate]

I know that this program is not using the static variable in an appropriate way, but it shows how to reproduce a behavior I have seen :
Main.cpp :
int main(){
MyObject* p = new MyObject();
Header::i = 5;
printf("i %i\n", Header::i);
p->update();
return 0;
}
MyObject.cpp :
MyObject::MyObject(){
}
void MyObject::update(){
printf("i %i\n", Header::i);
}
Extern.h :
namespace Header {
static int i;
};
The output I get is :
i : 5
i : 0
Why don't I get 5 for both outputs ? Where does this 0come from ?
Could you explain how static variables work ?
Static variables have internal linkage which effectively means they are local to the compilation unit. Since you have the static variable declared in a header included in 2 source files, you basically have 2 distinct variables: one i local to MyObject.cpp and another, different i, local to main.cpp
You have one static variable per translation unit where you include the header, because static variables have internal linkage.
Where does this 0 come from ?
You've not initialized the variable in the second translation unit, and static variables are zero-initialized, that's where the 0 comes from.
In the standard (ยง3.6.2/2):
Variables with static storage duration (3.7.1) [...] shall be zero-initialized (8.5) before any other initialization takes place.[...]
You have two variables i
static int i;
because it has internal linkage. That means that each compilation unit where the corresponding header was included has its own object i and other compilation units know nothing about presnece of that object in this compilation unit.
If you will remove specifier static then the linker should issue a message that the variable is defined twice.
The same effect can be achieved if to place a variable in an unnamed namespace in C++ 2011. For example instead of
namespace Header {
static int i;
};
you could write
namespace {
int i;
};
In this case varaible i also has internal linkage. This is valid for C++ 2011.
You should not put static valiables in header files. That leads to every cpp file that includes that header to have a copy of that static local to its compilation unit.
What you could do is extern storage specifier:
Header:
namespace Header {
extern int i;
}
Cpp:
namespace Header {
int i = 0;
}
As an addition to the all the answers. WHY it happens, was already explained. However HOW to fix it, was suggested till now only by using static/extern approach. This is little bit C-like. Unles you don't have to use the header in C-part of the project with C-linkage, you could use C++.
So IF you have really to use something static in your code.
Either declare the variable as a member of a class:
header.h
MyGlobalVariableHoler
{
public: static int i;
};
main.cpp
// class' statics have has to be initialized, otherwise linker error.
int MyGlobalVariableHoler::i=0;
any_code.cpp
#include <header.h>
MyGlobalVariableHolder::i=4711;
Or use a singleton to avoid the explicit initialization
header.h
MyGlobalVariableHolder
{
MyGlobalVariableHolder(){i=0;}
public:
static MyGlobalVariableHolder & instance()
{
static MyGlobalVariableHolder inst;
return inst;
}
int i;
};
any_code.cpp
#include <header.h>
MyGlobalVariableHolder::instance().i=4711;
Its better to declare your variable with extern in your header file to specify that it has an external linkage. Otherwise the above behavior will occur or potential compile or link problems can happen.
static int i ; // i has internal linkage
extern int i ; // i has external linkage
You are getting confused with class level static variable with namespace level static variable. Both are accessed by X::y qualification, adding to confusion. Others have explained actual reason (at the compilation/linkage level).
The variable that is declared static only has scope in the file in which it is declared where as the variable declared without static can be accessed from other files using an extern declaration.

static variable cpp do not want to change

FileA.hpp:
static int a;
void change(int);
FileA.cpp
#include "FileA.hpp"
void change(int x) { a = x; }
main.cpp
#include "FileA.hpp"
#include <cstdlib>
#include <iostream>
int main()
{
a = 5;
std::cout<<a<<std::endl;
change(10);
std::cout<<a<<std::endl;
a = 20;
std::cout<<a<<std::endl;
system("Pause");
return 0;
}
My output is:
5
5
20
Can someone help me with this? Why variable 'a' don't want to change in function
which is in FileA.cpp.
How to fix this. When I make change(int x) inline in "FileA.hpp" it works fine.
The static keyword on a global variable gives that variable internal linkage. It means that any translation unit that has that definition will have its own copy of the object. So the a object that main.cpp sees and that FileA.cpp sees are different objects. change will modify one of them, but main will output the other.
If you were intending static to mean that the object has static storage duration, global variables (or variables at namespace scope in general) have static storage duration anyway. You don't need to mark them static. However, if you remove static, you'll have another problem; you'll have multiple definitions of a across translation units.
The correct way to do this is to declare a as extern in the FileA.hpp file:
extern int a;
Then in a single translation unit (probably in FileA.cpp, define the object:
int a;
This means that any object that includes FileA.hpp will have the declaration of a (which is fine) and only one translation unit will have the definition of a. Perfect.
You declare a in the header file, which when included creates two copies of it, one in main.cpp and one in FileA.cpp. When you do a = 5; you assign to the copy from main.cpp, while when calling the function change, it changes the copy in FileA.cpp.

Not able to understand static behaviour

I wrote in
// In file t.h
#ifndef __t_h__
#define __t_h__
static int abc;
#endif
--
//In main.c
#include <stdio.h>
#include "t.h"
int main()
{
abc++;printf("%d \n", abc);
test();
}
- -
//In test.c
#include <stdio.h>
#include "t.h"
void test()
{
abc++;
printf("%d \n", abc);
}
When I run the project I found the output of abc is 1 and 1.
But when I change it to int abc in t.h. The output of abc = 1 and 2.
Why static is not retaining the value when the control reaches to test.c file.
If it won't retain then why should not it provide an error as the static variable can not be shared between/among the files?
static variables has internal linkage which means each translation unit gets its own copy.
So in your program each .cpp file which includes t.h has its own copy of the static variable, which in turn means, there are two objects in the memory. You can try printing their addresses to confirm this, as they will be different.
That makes the situation pretty simple: if you change the object in one .cpp, it doesn't reflect in the other .cpp file, because the object in the other .cpp file is a different object. Why should it change?
But when you change it to int abc (i.e don't make it static), then each translation unit has same object. If you change it in one file, it will be reflected in other file also, as expected.
As for sharing, then yes, static objects can be shared between two functions in the same translation unit, but they cannot be shared between two translation units.
Search for translation unit on this site, you will get many topics on it. Read them, then you will understand it fully.
When the preprocessor is done with your code, main.c looks like
// omitted stuff from stdio
static int abc;
int main()
{
abc++;printf("%d \n", abc);
test();
}
and test.c looks like
// omitted stuff from stdio
static int abc;
void test()
{
abc++;
printf("%d \n", abc);
}
So each file contains its own variable abc that is not accessible from the other.
One solution would be to change t.h to
#ifndef __t_h__
#define __t_h__
extern int abc;
#endif
and then change main.c to
#include <stdio.h>
#include "t.h"
int abc;
int main()
{
abc++;printf("%d \n", abc);
test();
}
You can think about it like this: there's now only one int abc in your program, in main.c but test.c knows about its existence because the extern int abc tells test.c that somewhere else in the project there is an integer called abc that it will be able to find at link time.
When you declare a static variable in header file a copy of the static variable is created in each Translation unit where the header is included. So each of the translation units involved in your program has its own copy of abc now and hence you get the observed behavior.The behavior is not what you expected but it well defined one.
static variable can not be shared between/among the files?
No they cannot be! that is the very purpose of making them static
static variables have internal linkage. Their scope is restricted to the the translation unit in which they are declared. They cannot be accessed beyond the TU.If you want to share the same variable across different Translation units You should drop the static and use extern, which gives the variable an external linkage and hence visibility across different translation units.
Good Read:
How do I use extern to share variables between source files?
In C, static has two usages:
1, Use static keyword to limit the var's scope in the translation unit. To make this simple, if you have two files: a.c, b.c and you wrote:
static int varA;
in a.c, then this means varA could only be used in a.c, if you want to use varA in b.c, you should remove the static keyword, and add extern int varA; in b.c, what people usually do is we create another file called: a.h, and write extern int varA; in a.h, and we simply include "a.h" in b.c, so we could write every variable we want to extern in a.h and use a single include "a.h" to make these variables or functions legal in other .c files(i.e. source files)
2, Using static to define a local variable in a function, for instance:
int TheFunction()
{
static int var = 0;
return ++var;
}
Because you used the static keyword on a local variable var, this variable will not loss when TheFunction() is returned.
The first time you call TheFunction() you will get 1, the second time you call TheFunction() you will get 2, and so on.
Next, lets see the usage of static in C++.
Because any C++ complier can complie a C code, so the 2 usages above is also in C++.
another two usages is:
1, static member variable.
2, static member function.
Lets see the code directly:
#include <iostream>
using namespace std;
class Test
{
public:
Test() : m_nNormalVar(0)
{
}
public:
// You need to init this static var outside the class
// using the scope operator:
// int Test::m_nStaticVar = 0;
static int m_nStaticVar;
// You can init this const static var in the class.
const static int m_nConstStaticVar = 10;
// This is just a normal member var
int m_nNormalVar;
};
int Test::m_nStaticVar = 0;
int main(int argc, char *argv[])
{
Test a;
Test b;
a.m_nStaticVar++;
a.m_nNormalVar++;
cout << b.m_nStaticVar << endl;
cout << b.m_nNormalVar << endl;
return 0;
}
a and b are objects of class Test they have the same m_nStaticVar and the same m_nConstStaticVar, but they have their own m_nNormalVar this is a static member variable.
#include <iostream>
using namespace std;
class Utility
{
public:
// This is a static member function, you don't
// need to have a concrete object of this class
// to call this function.
static int SelectMax(int a, int b)
{
return a > b ? a : b;
}
};
int main(int argc, char *argv[])
{
// No objects of class Utility
cout << Utility::SelectMax(2, 1) << endl;
return 0;
}
So this is a static member function of a class in C++.
These four ways of static's usage is all I known, if there are still some other usages, please help to edit this post, thx:)
EDIT:
Add static global function
1, Use static keyword to limit the function's scope in the translation unit. To make this simple, if you have two files: a.c, b.c and you wrote:
static void StaticFunction();
in a.c, so you can only call StaticFunction() in a.c, if you want to call this function in b.c you should remove the static keyword and then delcare it before the usage. Or just declare it in a.h and include "a.h" in b.c

C++ Namespace member access in different files how to? how "namespace std" implemented?

I have declared the below namespace in sample.h
// namespace with identifier
namespace N1
{
int b = 80;
}
sample1.cpp use the above namespace declaration
#include <iostream>
#include "sample.h"
using namespace std;
using namespace N1;
int main(void)
{
cout << "b (in main) = " << b << endl;
foo(); //written in sample2.cpp
return 0;
}
sample2.cpp also use the namespace declared in sample.h
#include <iostream>
#include "sample.h"
using namespace std;
using namespace N1;
void foo(void)
{
cout << "b = " << b << endl;
}
when I compiled, I got the below errors
$> g++ sample1.cpp sample2.cpp
/tmp/ccB25lEF.o:(.data+0x0): multiple definition of `N1::b'
/tmp/cchLecEj.o:(.data+0x0): first defined here
Let me know how to resolve and how "namespace std" implemented to avoid this problem ?
Its not a problem of #ifndef guard.
Use extern in the header file as:
//sample.h
namespace N1
{
extern int b; //extern is MUST!
//DONT WRITE : extern int b = 80;
}
Then define it in .cpp file as:
//sample.cpp
namespace N1
{
int b = 80; //initialization should be here
}
Include guards will work only during compile time, but the error is at link time. This is because the sample.h is included in both compilation units and a variable N1::b is created in both.
If you really want a variable (not a const) you have to declare it as extern in the header, and create a memory location for it in a separate compilation unit:
// sample.h
#ifndef N1
#define N1
namespace N1 {
extern int b;
}
#endif
// sample.cpp
#include "sample.h"
namespace N1 {
int b = 80;
}
Isn't it just a case of a missing ifdef or pragma once in the sample.h file?
Every time you #include sample.h into a .cpp module it will create a new linker record for b giving you multiple defines on the link[1].
The int should be defined in sample.cpp, or somewhere else and simply extern int b in sample.h.
[1] some linkers will ignore this and you'll be able to link OK, but most of the time it will generate errors.
Your issue is that you have a definition of an object with external linkage in a header file which is included in two separate compilation units. The issue is independent of namespaces as such.
One solution is to make the header file include a declaration only, (e.g. see below) and place the definition on a single source file.
// sample.h
namespace N1
{
extern int b;
}
// sample.cc
namespace N1
{
int b = 80;
}
Another solution is to give the object internal linkage, although this will mean that you have multiple objects called b but this may not be an issue. For example, if b is supposed to be constant then this would work because const objects have internal linkage by default.
// sample.h
namespace N1
{
const int b = 80;
}
If all you want is to define a constant, try this instead:
namespace N1
{
enum MyEnum
{
b = 80
};
}
Include guards are a good idea for almost any .h file, but they're probably not your problem here. There are two main parts to the all-important One Definition Rule: the first says that each symbol may only be defined once per translation unit (which generally means a .cpp file). That's what include guards are for: they prevent a header from being included twice, which would lead to a symbol (like N::b) being defined more than once in the same translation unit (= .cpp file).
But this is not all, however. Some symbols, such as classes, non-inline functions, and some variable definitions can only be declared once for the entire program. This is not unreasonable: let's suppose you allowed defining an int value called MyInt as 40 in one translation unit and as 80 in another: how the compiler would know which one to use? Of course, you can declare such symbols more than once per program (but only once per translation unit) - or they would only be usable in the translation unit they were declared in. But you cannot define them in more than one translation unit.
Using enum was an easy way to avoid having to separate declaration and definition in your case (since enum isn't subject to the second version of the One Definition Rule), but if you really need a (non-const) global of int type, you could achieve it this way:
sample.h
namespace N1
{
// The extern keyword tells the compiler that this is is only
// a declaration and the variable is defined elsewhere.
extern int b;
}
sample1.cpp
#include "sample.h"
namespace N1
{
// This is the definition!
int b = 5;
}
void foo()
{
using namespace std;
cout<<N1:b<<endl;
}
sample2.cpp
#include "sample.h"
// No need to define N1::b, since it was already defined in sample1.cpp.
void bar()
{
using namespace std;
cout<<N1:b<<endl;
}
The program contains two definitions of the variable N1::b while there must be exactly one. The variable must be declared in the header with the extern and defined only in one source file.