static global std::unique_ptr disappears - c++

I probably misunderstood how static objects work. Suppose following
common.hpp
struct common {};
static std::unique_ptr<common> global_ptr;
foo.cpp
#include "common.hpp"
void bar();
int main()
{
global_ptr = std::make_unique<common>();
bar();
}
bar.cpp
#include "common.hpp"
void bar()
{
*global_ptr; // crashes, because global_ptr is empty
}
I am able to debug such situation, and &global_ptr is different in main() and bar(), why is that? global_ptr is definitely initialized in main(), I can use it without problem, but why global_ptr in bar() seems unitialized?

static variable at global and namespace scope means internal linkage.
The name can be referred to from all scopes in the current translation unit.
It means global_ptr in different translation unit are different objects. The static variable is not visible outside of its own translation unit. There might be many objects with the name global_ptr, but only one per translation unit.
If you just want a global variable, you could declare it in common.hpp as:
extern std::unique_ptr<common> global_ptr;
and define it in the cpp file (might be common.cpp):
std::unique_ptr<common> global_ptr;

Globals behave like your intended behavior without the static keyword.
Static means that the global is actually local to the translation unit.
Your confusion comes from the fact that static means different things in global scope and in function scope.

Related

Variable already defined in .obj; What is going on here?

head.h
#pragma once
namespace foo
{
int bar;
int funct1();
}
head.cpp
#include "head.h"
int foo::funct1()
{
return bar;
}
main.cpp
#include <iostream>
#include "head.h"
int main()
{
foo::bar = 1;
std::cout << foo::funct1() << std::endl;
return 0;
}
Error LNK2005 "int foo::bar" (?bar#foo##3HA) already defined in head.obj
I don't understand what is going on. I tried looking for the answer but everyone's questions are so specific to their code and don't even look close to the problem that I am having.
I am not including .cpp files into main. I am not redefining anything. I am literally just assigning 1 to the variable then returning it with a function in the same namespace. How is it being defined multiple times?
The header head.h is included in two compilation units head.cpp and main.cpp. So the variable bar is defined twice. You could declare the variable without its definition the following way
#pragma once
namespace foo
{
extern int bar;
int funct1();
}
and then define it in some cpp module.
This foo namespace-level bar declaration:
namespace foo
{
int bar;
}
is actually a definition.
To make it a declaration, mark the bar as extern in head.h:
namespace foo
{
extern int bar;
}
Then define it in head.cpp:
int foo::bar = 0;
head.h is included in both main.cpp and head.cpp.
So the variable is defined twice.
Possible Solution: make it inline. The "extern" solutions are also good, although older in approach.
namespace foo
{
inline int bar;
}
How is it being defined multiple times?
It is defined once in head.cpp and once in main.cpp. That is a total of two times. This violates the one definition rule, which states that there may only be one definition for every variable.
int bar;
This is a definition of a variable. You've included it into two translation units.
A variable can be declared without definition in an extern declaration:
extern int bar;
Replace the definition with such declaration, and put the definition into exactly one translation unit.
I am not redefining anything. I am literally just assigning 1 to the variable
You're redefining the variable!
head.cpp has one via #include "head.h", and main.cpp has one via #include "head.h".
You need to merely declare it (unusual but not too strange) in the header:
extern int bar;
…then define it in one translation unit. This is just like what you do with static class members (albeit with slightly different syntax).
Since C++17, you may do this by instead plopping the inline keyword on to your definition.
Alternatively, avoid mutable globals…
Do carefully note that foo is not a class, but a namespace. When you declare a free variable in the header file:
int bar;
And then #include this header file multiple times (into different CPP files, causing multiple translation unit compilations), you'd get a linker error. Everyone knows it.
And, you'd add extern attribute at the declaration, and define the variable elsewhere in one of the CPP/C file.
Putting a global variable into a namespace is nothing but giving the global variable a different name. Think if foo::bar as foo__NS__bar, and hence you must add extern in the header and define foo::bar at some locatoin.
Note that this is different from a non-static member variable of a class. A class variable doesn't need to be defined/declared this way since the class is a type. Each instantiated variable of class-type would have a separate copy of the variable.
Further to that, when you add a static variable in the class, you are giving that logically global variable another name. Thence, you must have that static-variable defined one of the CPP file.

why static variable in a class gives a linking error?

Why static variable in a class has to be re-initialised as a global in the file?
Otherwise, it gives a linking error. What is the theory behind it? I understand that the static variable will be in the Data Segment.
my_class.h
class my_class
{
public:
static int m_fid;
void get_fid();
};
my_class.cpp:
#include <iostream>
using namespace std;
int main()
{
my_class t;
/**this gives a linking error */
my_class::m_fid = 0;
return 0;
}
First of all the definition of static variable is wrong.
Instead of my_class::m_fid = 0; you should define as int my_class::m_fid = 0; when you do that there will be no more linker error..
Another thing as per standard...
The definition for a static data member shall appear in a namespace
scope enclosing the member’s class definition.
Yes, static variables (wherever they are declared) go into the data segment.
static means different things depending where it's used, though.
At file or namespace scope, it means the variable is specific to the .cpp file (translation unit).
At local scope, it means the variable is specific to that scope, which may be specific to the translation unit, or shared between translation units if it's in an inline function.
At class scope, a static member declaration inside the class is effectively (almost) the same as one outside the class with the extern specifier.
Like a variable declared extern, a static member is only considered to be declared (and not defined) until a definition is reached.
There is an exception for some static const and static constexpr members, that they may be initialized inside the class and then immediately used, subject to the restriction that the address of the member is never used.

Can anyone explain this portion of the C++0x draft standard?

From ISO Standard Draft: §3.0/9:
n3234 says:
A name used in more than one translation unit can potentially refer to the
same entity in these translationunits depending on the linkage (3.5) of the
name specified in each translation unit.
Can anyone explain this point with an example, please?
What is that statement actually saying? Can any one prove this point in terms of a program?
Sure! What this is saying is that if you have multiple source files (translation units) that both use some name (for example, the name of a variable, class or function), then it's possible that those different files are talking about the same variable, class, or function, assuming that that entity was declared in a way that makes it visible across different files (that is, depending on its linkage).
For example, if I have this file:
A.cpp:
int globalInt;
int main() {
globalInt = 137;
}
And this one here:
B.cpp:
extern int globalInt;
void foo() {
globalInt = 42;
}
Then in both files, the name globalInt refers to the global int variable globalInt defined in A.cpp. That's all that this point is saying.
Note, however, that if I declare globalInt without external linkage, then the two files will be talking about different variables. For example, in this case:
C.cpp:
static int globalInt;
int main() {
globalInt = 137;
}
D.cpp:
static int globalInt;
void foo() {
globalInt = 42;
}
Now the globalInt variable referenced in C.cpp is not the same as the one in D.cpp, even though they have the same name.
Hope this helps!
Ah, standards... let's obfuscate the obvious.
It's saying that, if you use a global variable with the same name in two different source files, they will be the same variable if they are extern or don't specify at all, but if any of them are declared static then those will be completely independent because they're only visible in that source file.
int a; // can be seen in other files; this may be duplicated in multiple source files
static int b; // can only be used in this file
extern int c; // explicitly using a visible variable "c" defined in another file
("Linkage" is the static/extern/default global, or auto which is almost never mentioned since it means "allocated on the stack", which is the default for variables declared inside a function and obviously not meaningful for a declaration outside a function. "Translation unit" is a common way for standards to avoid mentioning "files".)

Use of static variables and functions in global scope

Is there a use for flagging a variable as static, when it lies in the global scope of a .cpp file, not in a function?
Can you use the static keyword for functions as well? If yes, what is their use?
Yes, if you want to declare file-scope variable, then static keyword is necessary. static variables declared in one translation unit cannot be referred to from another translation unit.
By the way, use of static keyword is deprecated in C++03.
The section $7.3.1.1/2 from the C++ Standard (2003) reads,
The use of the static keyword is
deprecated when declaring objects in a
namespace scope; the
unnamed-namespace provides a superior
alternative.
C++ prefers unnamed namespace over static keyword. See this topic:
Superiority of unnamed namespace over static?
In this case, keyword static means the function or variable can only be used by code in the same cpp file. The associated symbol will not be exported and won't be usable by other modules.
This is good practice to avoid name clashing in big software when you know your global functions or variables are not needed in other modules.
Taking as an example -
// At global scope
int globalVar; // Equivalent to static int globalVar;
// They share the same scope
// Static variables are guaranteed to be initialized to zero even though
// you don't explicitly initialize them.
// At function/local scope
void foo()
{
static int staticVar ; // staticVar retains it's value during various function
// function calls to foo();
}
They both cease to exist only when the program terminates/exits.

access const variables accross translation units

In C++, const variables are implicitly hidden from other translation units. Is is possible to prevent that?
Yes, prefix the definition with extern eg.
extern const int x = 10;
Use the extern keyword:
extern const int x = 10;
This forces the variable to have external linkage.
For namespace-scope variables this is usually the default, and you'd use static (or, better, an anonymous namespace) to force internal linkage.
I didn't actually know that namespace-scope const variables have internal linkage by default until I read your question and tried it out, so thanks for that. Learn something new every day!
It can be achieved by means of the extern keyword:
// a.cpp
extern const int x = 10; // definition
// b.cpp
extern const int x; // declaration
The effect this will have is that you will not need to recompile b if the value of the constant changes in a, but at the same time you loose the ability to use x as a compile time constant inside b.cpp (i.e. you will not be able to write int array[x];).
If there isn't a very strong reason for this, I would rather have the constant defined in a header file and included in all translation units that require it;
// c.h
const int x = 10;
// a.cpp
#include "c.h"
// b.cpp
#include "c.h"
You will have to recompile all translation units that depend on the constant with each change, but you will be able to use it at compile time in all translation units. The limitation of this approach is that if you change the constant and only recompile some of the translation units, the value of the constant will be inconsistent (this is a violation of the ODR).