How to use public static variables in C++ - c++

There doesn't seem to be a clear, concise example of real word use of a public static variable in C++ from multiple files on StackOverflow.
There are many examples showing how to use static variables in a single C++ translation unit, and many questions about the precise nature of the various uses of the static keyword, but as a programmer more experienced with C# I found it hard to scrape together what I needed to simply "have a static variable on a class and use it elsewhere" like you would in C# or Java.
Here I will try to demonstrate what I discovered in the most straightforward way. I hope that others will then improve on the answer and give more technical details for those that are interested.
SomeClass.h
In the header file for the class where we want to have a static variable, we just declare it static like we would in C# or Java. Don't try to initialise the variable here; C++ doesn't like that.
class SomeClass
{
public:
static bool some_flag;
};
SomeClass.cpp
In the cpp file for the class, we create the storage for the static variable, just like we would provide the implementation for a member function. Here we can initialise the variable. So far, this is going swimmingly!
#include "SomeClass.h"
bool SomeClass::some_flag = true;
SomeOtherClass.cpp
Here is where I ran into problems. If we try to just access SomeClass::some_flag from elsewhere (which, let's face it, is probably the reason you wanted a public static variable in the first place), the linker will complain that it doesn't know where it lives. We've told the compiler that the static variable exists, so the compiler is happy. The problem is that in this other translation unit we've never specified where that static variable is stored. You may be tempted to try redeclaring the storage, and hoping the linker resolves them both as "the some_flag I declared in SomeClass.h", but it won't. It will complain that you've given the variable two homes, which of course is not what you meant.
What we need to do is to tell the linker that the storage for some_flag lives elsewhere, and that it will be found once we try to put all the translation units together at link time. We use the extern keyword for this.
#include "SomeOtherClass.h"
#include "SomeClass.h"
extern bool SomeClass::some_flag;
void SomeOtherClass::SomeOtherFunction()
{
SomeClass::some_flag = true;
};
Voila! The compiler is happy, the linker is happy, and hopefully the programmer is also happy.
I now leave this open for a discussion on how I should not have used a public variable, could have just passed an instance of SomeClass through the 87 layers of code that's between it and the usage, should have used some feature coming in C++23, should have used boost::obscurething etc. etc.
I do however welcome any alternative approaches to this fundamental problem that are true to the usage I've demonstrated here.

Here is where I ran into problems. If we try to just access SomeClass::some_flag from elsewhere [...], the linker will complain that it doesn't know where it lives.
The linker won't complain, as long as you link with the translation unit that defines the variable (SomeClass.cpp).
extern bool SomeClass::some_flag;
This declaration is neither allowed, nor is it necessary. The class definition that contains the variable declaration is sufficient for the compiler, and the variable definition in SomeClass.cpp is sufficient for the linker. Demo
Don't try to initialise the variable here; C++ doesn't like that.
I do however welcome any alternative approaches to this fundamental problem
You could simply use an inline variable (since C++17):
class SomeClass
{
public:
inline static bool some_flag = true;

The answer, in summary form, for people who just want the code so they can get back to work:
SomeClass.h
#pragma once
class SomeClass
{
public:
static bool some_flag;
};
SomeClass.cpp
#include "SomeClass.h"
bool SomeClass::some_flag = true;
SomeOtherClass.cpp
#include "SomeOtherClass.h"
#include "SomeClass.h"
extern bool SomeClass::some_flag;
void SomeOtherClass::SomeOtherFunction()
{
SomeClass::some_flag = true;
}

Related

Scope of a static variable to several files C++ [duplicate]

Well, I'm learning C++ and never really learned how to do stuff that is not OO.
I'm trying to get a bit more experience coding in C style.
GobalInformation.h
#pragma once
#ifndef GLOBALINFORMATION_H
#define GLOBALINFORMATION_H
#include "MapInformation.h"
namespace gi {
MapInformation mapInf;
};
#endif
I would like to be able to access gi::mapInf from every header and cpp in my project. Right now I'm including globalinformation.h in every header, so I'm getting linker errors with multiple definitions.
How can I work around the problem?
In header file only do
namespace gi {
extern MapInformation mapInf;
};
In CPP file provide the actual definition.
namespace gi {
MapInformation mapInf;
};
It will work as you intend.
If you are using the MapInformation across dynamic link library boundaries you might have to link against the library that includes the definition cpp file. Also on Window you might have to use dllimport/dllexport
Be aware that having globals in multiple compilation units can easily lead to order-of-initialization problems. You may wish to consider replacing each global with a function that returns a reference. In your case, put this in one cpp file and declare it in the header:
namespace gi {
MapInformation& getMapInf()
{
static MapInformation result;
return result;
}
}
Global variables are C, but namespaces are C++. There is a good discussion on using global variables and how they can be replaced by Singleton pattern: Globals and Singletons
And here is a simple sample: CPP/Classes/Singleton
Perhaps a better solution is to create a global object that contains all your global data. Then pass a smart pointer to the classes that actually need to access this shared global data.
Example:
class GlobalData
{
public:
int ticks_;
};
//Other file
class ThatNeedsGlobalData
{
public:
ThatNeedsGlobalData(std::shared_ptr<GlobalData> globalData);
};
This will save you some trouble.
Good luck!
Here are a few things that you need to take care of while trying to use global variables the way you have used.
Ensure that all the header files that the header files that GobalInformation.h includes are also enclosed insides #ifndefs. (I could not see mapinformation.h so I assume you have done it)
Just like CPP, C compiler also does not ensure order of the initialization of variables in different translation units(different C/CPP files).
Hence declare the header file as
//GlobalInformation.h
namespace gi {
extern MapInformation mapInf;
};
In a function that you know would be called first initialize the variable. This way lazy-initialization can also be acheived in C.

Global variables in header only library

I'm writing a header-only logger library and I need global variables to store current logger settings (output flags, log file descriptor etc.). My thoughts:
I can't declare variables as extern, as i don't have access to the translation units to define them
I can't just define global variables in header as it will lead to multiple definitions
static variables in header's functions may seem good at the first glance, but the fact is that every translation unit will have it's own copy of 'global' variable, which is awkward and definitely wrong
I don't also think it is possible to avoid global variables in my case (even though that's what i'd like to do) as i obviously have to store settings somehow between log function calls
Is there any variants i didn't consider yet? Is there any other way to have global variables using headers only.
p.s. I'm looking for both c99/c++11 compatible solution with possible gcc hacks (gcc >= 4.8)
One approach is to hide options behind a function that returns a reference to a local static option. As long as the ODR is not violated (e.g. by some macro-dependent changes of the functions), it is guaranteed that the local static variables are unique across your program. As a simple example, this can be in the header file:
inline bool& someOption()
{
static bool opt = false;
return opt;
}
and in a translation unit:
someOption() = true;
It would probably be useful to group your options into a struct and apply the above technique to an instance to this struct.
Note that this approach is limited to C++ (thanks to #rici for the hint), and might only accidently work out in C using gcc.
Structure your library like follows:
MyLibrary.h:
extern int foo;
extern int bar;
...
#ifdef MY_LIBRARY_IMPL
int foo;
int bar;
...
#endif
Then, in the library documentation, specify that in exactly one translation unit, the user of the library should #define MY_LIBRARY_IMPL before including the header file.

undefined reference to protected static member. How do I solve it? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In robots.hpp I have a class, robots. I want each robot to have a pointer to another robot, the one that was declared last. I also want each to have a unique id. For this I have a variable that counts the number of robots.
It seems that I can't initialise my static variables in the class definition. I looked up how to solve that, and found something recommending initialising them in robots.cpp. However, that gives me an error saying that they are protected, and so I can't do that. So now I have a function that is called by the constructor only once, at the beginning.
However, that is giving me an error saying that I can't do that, because they haven't been defined yet.
The class definition in robots.hpp:
class robot
{
public:
///initialiser.
robot();
[...]
///initialises all robots
void initrobots();
///id of robot
const uint_least8_t id=NumOfRobots++;
static bool hasBeenInitialised;
protected:
///number of robots.
static uint_least8_t NumOfRobots;
///pointer to the next robot that needs pointing to.
static robot* poiRobot;
[...]
///pointer to next robot
robot* nextRobot;
};
robots.cpp:
bool robot::hasBeenInitialised=false;
void robot::initrobots(){
poiRobot=NULL;
NumOfRobots=0;
}
robot::robot(){
if(!hasBeenInitialised){
initrobots();
hasBeenInitialised=true;
}
[...]
}
The code that generates this error is this:
#include <cstdint>
#include <cstdlib>
class robot
{
public:
///initialiser.
robot();
//[...]
///initialises all robots
void initrobots();
///id of robot
const uint_least8_t id=NumOfRobots++;
static bool hasBeenInitialised;
protected:
///number of robots.
static uint_least8_t NumOfRobots;
///pointer to the next robot that needs pointing to.
static robot* poiRobot;
//[...]
///pointer to next robot
robot* nextRobot;
};
bool robot::hasBeenInitialised=false;
void robot::initrobots(){
poiRobot=NULL;
NumOfRobots=0;
}
robot::robot(){
if(!hasBeenInitialised){
initrobots();
hasBeenInitialised=true;
}
}
int main(){
return 0;
}
If I compile it it doesn't complain, but it does complain if I build it (using geany to do the things separately, c++11 standard(otherwise cstdint complains))
I would like the code to make poiRobot a pointer to null, and NumofRobots equal to 0.
You should be able to get rid of static bool hasBeenInitialised; and bool robot::hasBeenInitialised=false; as well as your initialization function and just declare uint_least8_t robot::NumOfRobots = 0; and robot* robot::poiRobot = nullptr directly in your cpp file. This way they initialize themselves to 0 and null automatically. As mentioned in the comments this is valid, protected static variables should be able to be defined in the source file in this manner.
Edit: In regards to the code you posted in your edit, it looks like you are never defining robot::poiRobot and robot::NumRobots. Did you try the code I posted above?
Basically, each cpp file in your project must be compiled into a translation unit by the compiler. Then the linker comes through and takes all of the translation unit's and links them together. Any cpp file that sees your robot class will see that you've promised that those 2 variables exist somewhere, and therefore when you use them it will allow it (as far is it is concerned, they exist and are good to go). When the linker comes along it will see references to those variables and try to find which translation unit they were defined in so that it can do its job (link everything together). At this point, it won't see a definition in any translation unit, and that is why it gives you that error.
uint_least8_t robot::NumOfRobots = 0; and robot* robot::poiRobot = nullptr are the definitions you are looking for, and should go in your cpp file. If after using those you get another error about them being protected as you had hinted at earlier, post that code so we can see why that is happening.
Edit 2 in regards to "It seems that I can't initialise my static variables in the class definition.": When you put that definition in the header file, each cpp file that includes your header will define it's own version of that variable. When the linker goes to link everything it will see multiple definitions in different translation units for the same variable and that violates the "One Definition Rule" in C++ (ODR). That is why it will give you an error. It is correct to put it in robots.cpp so only 1 translation unit (robots.cpp in this case) will have the definition. Then you have to make sure that robots.cpp is being compiled in your project so that the translation unit is available for the linker... as you could mistakenly just include robots.h in your source files, but never tell the compiler to compile robots.cpp.

C++ global pointer shared by different files

So I am trying to make a C++ / OpenGL program (using Visual Studio 2010) that deals with Keyboard Input using a class called Operation. The point is to learn a few things since I'm new to both C++ and OpenGL.
I'm using an array 'bool keysDown[256]' to store which keys are pressed. Likewise I want to make an array of operations 'Operation *keyOps[256]', to operate those keys.
And here comes my problem, most of those keys will have no operation so I want an Operation class that will do absolutely nothing, but I only need one global instance/pointer that different files can use.
Now what I wanted to do, was to somehow create a single instance of this 'no operation' class and make it usable in any files that include this header without needing to declare it in each file. (Something like NULL, only in the shape of an Operation class)
So far my 'solution' was to use a namespace like this,
(operation.h)
#ifndef _OPERATION_H
#define _OPERATION_H
#include <iostream>
#include <GL\glut.h>
namespace operations{
class Operation{
protected:
std::string _name;
public:
Operation(std::string name) : _name(name){}
virtual void operate()=0;
std::string getName(){return _name;}
};
(...)
class OPnop: public Operation{
public:
OPnop(): Operation("No operation"){}
void operate(){}
};
static OPnop OPNOP;
Operation* nop(); //implemented in .cpp > {return &OPNOP;}
(...)
};
#endif
Other files can get a pointer to the OPNOP instance by using the operations::nop() function. I've tested and it works, but I'm not sure this works as intended in the background.
I have been searching for extern and static usage on global variables, but I probably didn't understand it all and I didn't find an answer I could relate to my problem. If I'm not mistaken extern variables have to be declared in other files too while static creates a different variable for each file including it.
So my question is, is there a way to declare/instantiate this 'no operation' so that all the files including this header will have access to the same unique instance directly without having to use a function?
Indeed the static keyword has a different meaning in the namespace context than the class context. I believe what you want to do is declare it as extern in your header, and in the implementation (.cpp) file initialize it once. Take a look at this question.
I did something similar here.
I'm using a Gesture class with a single global instance as gGesture to handle all the user interactions.
// .h file
struct Gesture_{
int fingers;
int taps;
eGestureAction action;
bool continious;
};
typedef struct Gesture_ Gesture;
extern Gesture gGesture;
To answer your question on static vs extern, the extern avoids linker problems by not adding same symbol to all translation units.
Notes:
The code was originally intended to work in a C based project, but I think you'll get the idea.
The Gesture object is intended for Touch based devices.

static initialization confusion

I am getting very confused in some concepts in c++. For ex: I have following two files
//file1.cpp
class test
{
static int s;
public:
test(){s++;}
};
static test t;
int test::s=5;
//file2.cpp
#include<iostream>
using namespace std;
class test
{
static int s;
public:
test(){s++;}
static int get()
{
return s;
}
};
static test t;
int main()
{
cout<<test::get()<<endl;
}
Now My question is :
1. How two files link successfully even if they have different class definitions?
2. Are the static member s of two classes related because I get output as 7.
Please explain this concept of statics.
They link because the linker knows almost nothing about the C++ language. However, if you do this, you have broken the One Definition Rule, and the behaviour of your program will be undefined. writing invalid code is not a good way of learning C++. Also, you seem to be having a lot of questions about static variables - the concept is really not all that complex - which C++ textbook are you using that does not explain it well?
The classes are (as far as the linker is concerned) identical. get() is just an inline function the linker never sees.
static in a class doesn't limit the member to file scope, but makes it global for all class instances.
[edit:] You'd get an linker error if you would put int test::s=5; into the second file as well.
Static is a strange beast in C++, that has different meanings depending on the context.
In File1.cpp, "static int s" in the class definition indicates that s is a static member, that is, is common to all instances of test.
The "static test t", though, has a different meaning: a static global variable only exists in the compilation unit, and will not be visible by other units. This is to avoid linker confusion if you were using the same name for two different things. In modern C++, one would use anonymous namespaces for this:
namespace
{
test t;
}
This means that t inside File1.cpp and t inside File2.cpp are separate objects.
In File2.cpp, you also defined a static method get: a static method is a method that belongs to the class instead of the instance, and that can only access static members of the class.
A last use of static, that you did not use in your example, is the local static variable. A local static variable is initialised the first time it gets executed, and keeps its value throughout the execution, a bit like a global variable with a local scope:
int add()
{
static value = 0;
value++;
return value;
}
Calling add() repetitively will return 1, then 2, then 3... This local static construct can be useful for local caches for example.
How two files link successfully even if they have different class definitions?
You violated the One Definition Rule (ODR) by defining the same class differently in different translation units. That invokes the dreaded Undefined Behavior. Which means the code is allows to do anything, including, but not limited to, doing what you wanted, formatting your hard disk, or causing an un-accounted for eclipse of the sun.
Note that compilers/linker are not requested to detect ODR violations.
Are the static member s of two classes related because I get output as 7.
Maybe they are, maybe they are not. Really, undefined behavior might do just anything. What you see is just an artifact of however your compiler and linker are implemented.
A likely implementation will happily link all references to test::s to the same instance, but let each translation unit have - and link to - their own t object. (Since the class has only inline functions, the linker most likely never even sees anything of test except for test::s and those t instances.)
Unnice side-effect of how C++ actually works. Use namespaces to make the class names different to outside.
In past I had used the quite burdensome in practice rule: every library and file has to have a private namespace for to avoid such link conflicts. Or put the utility classes right into the main class definition. Anyway: not to pollute global namespace and most importantly ensure uniqueness of names across the whole project. (Writing that now I notice that I used pretty much verbatim the concept from Java.)
My search for equivalent of C's static in C++ was unfruitful...