How to extern global smart pointers that are assigned within SetUpTestSuite? - c++

I have a couple global pointers defined in a UtTestBase.hpp which are to be used by the files that include it (e.g: UtTest1.cpp).
SetUpTestSuite() is static and thus performs a shared set up for all the tests. I view it as preconfiguration. Doing the way I have would complain about multiple definitions of the globals however using extern for each doesn't work either.
Using extern errors out
namespace TEST
{
extern std::weak_ptr<int> weakPtr;
extern std::shared_ptr<int> sharedInt;
// ...
}
// errors
undefined reference to `weakPtr' in line "weakPtr = sharedInt;"
undefined reference to `sharedInt' in line "sharedInt = std::make_shared<int>();"
From what I have seen the usage of extern involves declaring the variables in a header and defining in a respective source file that uses it
What's the way around? static inline is other option but does it make sense for each file to have a separate instance of a global given they are assigned in SetUpTestSuite()?
UtTestBase.hpp
namespace TEST
{
std::weak_ptr<int> weakPtr;
std::shared_ptr<int> sharedInt;
struct UtTestBase
{
static void SetUpTestSuite()
{
sharedInt = std::make_shared<int>();
weakPtr = sharedInt;
}
// .. some common methods
};
}
UtTestBase.cpp
#include "UtTestBase.hpp"
namespace TEST
{
TEST_F(UtTestBase, Test1)
{
// ...
}
}
UtTest1.cpp
#include "UtTestBase.hpp"
namespace TEST
{
struct UtTest1 : public UtTestBase
{
void SetUp() override
{
// do init for a local test
}
// should have sharedInt and weakPtr assigned
};
}

The reason for the compile error with extern is that this only references the global variable. One of the translation units (exactly one!) has to define it, too. So, in the header, you need it declared with extern, and in one(!) of the cpp files, it additionally needs to be defined without extern.
If you don't define the variable anywhere (and only reference it with extern), the linker will complain that the variable doesn't exist - that's the error messages you're getting.
Here's a simple example with an int.
Header:
//Declare that the variable exists, don't actually create it
extern int g_whatever;
CPP file 1:
#include "Header"
//Create (define) the variable
int g_whatever;
CPP file 2, 3, ...:
#include "Header"
//Use g_whatever, *without* defining it again
This is independent of where you actually initialize the global variable. You could put the definition into UtTestBase.cpp, for example.
For a more in-depth explanation, see: How do I use extern to share variables between source files?

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.

Error C2011 'vars::strct': 'struct' type redefinition

vars.cpp:
#pragma once
#include "vars.h"
namespace vars
{
struct strct
{
bool enabled = false;
};
}
vars.h:
#pragma once
namespace vars
{
extern struct strct
{
bool enabled = false;
};
}
extern vars::strct *variables = new vars::strct[ 6 ];
I am getting 'vars::strct': 'struct' type redefinition in vars.cpp
What's the issue?
You have defined your struct twice, this clashes with the one definition rule, thus the error. If you include the vars.h file in vars.cpp you will have that struct defined in your vars.cpp file.
Note
You do not need the extern keyword in your vars.h file because you define a struct and not an instance of it to be used globally. See When to use extern in C++ for more information.
Also, you have used #pragma once in your .cpp file. In most cases you do not include .cpp files and thus it is redundant.
There are a couple things going wrong here.
extern is a Storage Class Specifier used as a promise to the compiler that a variable exists even if it has not yet found the definition of it. The variable can be safely used and the linker will take care of tracking where it has been defined later.
You do not need to define a type as extern and you may be receiving a diagnostic telling you this.
So fix 1: Remove extern from the type.
#pragma once
namespace vars
{
struct strct
{
bool enabled = false;
};
}
extern vars::strct *variables = new vars::strct[ 6 ];
Now when vars.cpp is compiled, vars.h will be includided, transforming vars.cpp into
#pragma once
namespace vars
{
extern struct strct
{
bool enabled = false;
};
}
extern vars::strct *variables = new vars::strct[ 6 ];
namespace vars
{
struct strct
{
bool enabled = false;
};
}
And it's obvious that strct is defined twice. Vars.cpp does not need it's own definition. Remove it.
What vars.cpp does need is to make good on the promise that somewhere variables exists, bringing us to problem 2.
extern vars::strct *variables = new vars::strct[ 6 ];
An extern variable is a promise that a variable exists. There is no variables yet, so initializing it is iffy. The compiler seems to allow it, but the compiler allows a lot of human stupidity.
In general you do not want variable definitions in headers because all files that include a header get a copy of the header. #pragma once will make reasonably sure (too my knowledge there are still a few failure cases) that the header only gets included once per Translation Unit. But each translation unit will have its own definition and you're right back into sorting out multiple definition errors.
Fix 2: What you really want is
vars.h
#pragma once
namespace vars
{
struct strct
{
bool enabled = false;
};
}
extern vars::strct *variables; // variables exists somewhere
and vars.cpp
#include "vars.h"
vars::strct *variables = new vars::strct[ 6 ]; // variables exists here
Now there is one and only one variables and anyone who #include "vars.h" can use it, assuming they compile and link vars.cpp.
Note the #pragma once has been removed from vars.cpp. It is unnecessary. If you find yourself including cpp files, you've gotten lost somewhere. Don't do it.

using extern keyword for user defined types in c++

I want to use extern keyword for user defined types. This means I've declared object in one file and defined it in other file. I've read that extern keyword is used to declare the variable without defining it. extern keyword is useful when program is split into multiple source files and global variable needs to be used by each of them. Please correct me If I am wrong somewhere.
Here is the programs I've written but unfortunately I am doing something wrong or missing something so I am getting compiler errors.
Prog1.cpp
#include <iostream>
using std::cout;
class test
{
public:
void fun();
};
void test::fun()
{
cout<<"fun() in test\n";
}
test t;
Prog2.cpp
#include <iostream>
using std::cout;
extern test t;
int main()
{
t.fun();
}
Now when I compile these 2 using
g++ -o prog1.cpp prog2.cpp
compiler gives me following errors in prog2.cpp
error: 'test' does not name a type
error: 't' was not declared in this scope
Please help me to know what I've done wrong here.
extern tells the compiler that the definition of t is somewhere else, but the compiler still needs the defintiion of test, as you're using t.fun() to compile Prog2.cpp.
So the solution is, write test.h where you define the class, and then define test t in Prog2.cpp as usual. Include test.h in your Prog2.cpp so that it may know the definition of test. Then build it.
test.h:
#include <iostream>
using std::cout;
class test //definition of test
{
public:
void fun()
{
cout<<"fun() in test\n";
}
};
Prog1.cpp:
#include "test.h"
test t; //definition of t
Prog2.cpp:
#include <iostream>
#include "test.h"
using std::cout;
extern test t; //the definition of t is somewhere else (in some .o)
//and the definition of test is in test.h
int main()
{
t.fun();
}
Now your code should compile and link.
Note that the definition of t is needed by the linker at link-time, so it will search for it in other .o files, but the definition of test is needed by the compiler, at compile-time.
Now it should be obvious that you can put the extern test t; in the header itself so that you dont have to write it in every .cpp file where you want to use the object defined in Prog1.cpp file (which is turned into Prog1.o by the compiler).
Put the extern keyword in the header, not the cpp file. It is the job of the header to tell the compiler there is an externally defined object somewhere.
For example:
program.h (mostly declarations)
struct UserDefinedType
{
void do_stuff();
};
// declare your global object in the header
// so that the compiler knows its name when
// compiling sources that can not otherwise see
// the object
extern UserDefinedType global_udt;
program.cpp (mostly definitions)
#include "program.h"
// define the member functions here
void UserDefinedType::do_stuff()
{
}
// define the global object here
UserDefinedType global_udt;
main.cpp (use the definitions that have been declared in the header)
#include "program.h" // tells the compiler about global_udt
int main()
{
// call the global object that is defined
// in a different source file (program.cpp)
global_udt.do_stuff();
}
NOTE: If we didn't declare the object global_udt in the header file then main.cpp would not know of its existence and the compiler would complain if we tried to use it.
So the header needs to only declare the object and not define it hence the extern keyword is needed.
Please note that a variable declared outside the class scope is a variable with external linkage(if not explicitly used the static keyword) or with internal linkage(if the static keyword is put in the left of the variable type), extern is necessary if you want to use it in multiple files.
Suppose this file is called MyVariable.h
int myNumber = 0; // Initialization of the variable myNumber, external linkage
static int myStaticNumber; // Initialization of the variable myStaticNumber, internal linkage(only the file in which it's declared)
And this file is OtherFile.cpp
extern int myNumber; // Not a initialization because it's already initialized in another file, works fine
extern int myStaticNumber; // ERROR, this variable has internal linkage!!
You may wonder why myStaticNumber was initialized and not just declared, that occurs because static variables are initialized to their default values by default.

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.

Is there any possible use of using extern variable in a file that is not included in any other file?

I've encountered many examples on the web, that have extern int x in main.c, where the main function lies.
The only use of extern I'm aware of, is to make a declaration in another file, and use it in another file, after defining it.
Like :
a.h : extern int x;
a.c : int x = 5;
main.c :
#include "a.h" // and start using x
The 1st case seems redundant to me.
So,
Is there any possible use of using an extern variable in a file that is not included in any other file?
extern tells the compiler that x exists in a different module and should be linked from elsewhere. Putting it in main.c directly just avoids pulling in a header (which would be included in-line anyways)
Just like in a header, x still needs to exist in another .c module where it isn't defined extern.
extern variable has basically two functions one is to use the variable in the other file and the other is to access global variables as in the following code.
int x=10;
int main()
{
int x=20;
cout<<x; //refers to x=20
if(x==20)
{
extern int x;
cout<<x; //refers to the global x that is x=10
}
}
Of course. Using extern in a file lets you use that variable in that file. It doesn't have to be included anywhere else.
The use of extern causes the object to have external linkage; to
instantiate a template with a object (and not a value or a type), the
object has to have external linkage (at least in C++03). Most objects
defined in namespace scope have global linkage, but const objects don't.
So you have something like:
template <char const* n>
class Toto { /* ... */ };
char const n1[] = "abc";
Toto<n1> t1; // Illegal...
extern char const n2[] = "xyz";
Toto<n2> t2; // Legal...
It's sort of a special case, but it has led me (once or twice) to use
extern in an unnamed namespace in a source file.