Why must my global variable be declared as a pointer? - c++

When compiling my C++ program I receive no errors, however within unordered_map the hash function fails, attempting to mod by 0. (Line 345 of hashtable_policy.h of stl)
I've found a fix, but don't know why I'm having the problem to begin with.
My struct looks like this, (Sorry for the specific code.)
struct Player {
private:
Entity& entity = entityManager->create();
public:
Player() {
entity.addComponent(new PositionComponent(0, 0)); // Add component uses the unordered map.
}
};
Player playerOne; // Error perpetuates through constructor.
However, if I declare playerOne as a pointer, like so:
Player* playerOne;
and then call:
playerOne = new Player();
I do not have any issues.
I've been searching - with no success. What could I be doing wrong?

When you use a Player as a global, you've no idea if the entityManager (presumably another global) has been initialised yet - the order of initialisation of globals isn't defined.
When you use the pointer and initialise it with new (in main(), I presume), all the globals have been created by then, so the code works.
This highlights one of the reasons why global variables are a bad idea.

Related

C++ global extern constant defined at runtime available across multiple source files

I have an integer constant that is to be defined at runtime. This constant needs to be available globally and across multiple source files. I currently have the following simplified situation:
ClassA.h declares extern const int someConstant;
ClassA.cpp uses someConstant at some point.
Constants.h declares extern const int someConstant;
main.cpp includes ClassA.h and Constants.h, declares const int someConstant, and at some point during main() tries to initialize someConstant to the real value during runtime.
This works flawlessly with a char * constant that I use to have the name of the program globally available across all files, and it's declared and defined exactly like the one I'm trying to declare and define here but I can't get it to work with an int.
I get first an error: uninitialized const ‘someConstant’ [-fpermissive] at the line I'm declaring it in main.cpp, and later on I get an error: assignment of read-only variable ‘someConstant’ which I presume is because someConstant is getting default initialized to begin with.
Is there a way to do what I'm trying to achieve here? Thanks in advance!
EDIT (per request from #WhozCraig): Believe me: it is constant. The reason I'm not posting MCVE is because of three reasons: this is an assignment, the source is in Spanish, and because I really wanted to keep the question as general (and reusable) as possible. I started out writing the example and midway it striked me as not the clearest question. I'll try to explain again.
I'm asked to build a program that creates a process that in turn spawns two children (those in turn will spawn two more each, and so on). The program takes as single argument the number of generations it will have to spawn. Essentially creating sort of a binary tree of processes. Each process has to provide information about himself, his parent, the relationship with the original process, and his children (if any).
So, in the example above, ClassA is really a class containing information about the process (PID, PPID, children's PIDs, degree of relation with the original process, etc). For each fork I create a new instance of this class, so I can "save" this information and print it on screen.
When I'm defining the relationship with the original process, there's a single point in which I need to know the argument used when calling the program to check if this process has no children (to change the output of that particular process). That's the constant I need from main: the number of generations to be spawned, the "deepness" of the tree.
EDIT 2: I'll have to apologize, it's been a long day and I wasn't thinking straight. I switched the sources from C to C++ just to use some OO features and completely forgot to think inside of the OO paradigm. I just realized while I was explaining this that I might solve this with a static/class variable inside my class (initialized with the original process), it might not be constant (although semantically it is) but it should work, right? Moreover I also realized I could just initialize the children of the last generation with some impossible PID value and use that to check if it is the last generation.
Sorry guys and thank you for your help: it seems the question was valid but it was the wrong question to ask all along. New mantra: walk off the computer and relax.
But just to recap and to stay on point, it is absolutely impossible to create a global constant that would be defined at runtime in C++, like #Jerry101 says?
In C/C++, a const is defined at compile time. It cannot be set at runtime.
The reason you can set a const char *xyz; at runtime is this declares a non-const pointer to a const char. Tricky language.
So if you want an int that can be determined in main() and not changed afterwards, you can write a getter int xyz() that returns a static value that gets initialized in main() or in the getter.
(BTW, it's not a good idea to declare the same extern variable in more than one header file.)
As others have mentioned, your variable is far from being constant if you set it only at run-time. You cannot "travel back in time" and include a value gained during the program's execution into the program itself before it is being built.
What you can still do, of course, is to define which components of your program have which kind of access (read or write) to your variable.
If I were you, I would turn the global variable into a static member variable of a class with a public getter function and private setter function. Declare the code which needs to set the value as a friend.
class SomeConstant
{
public:
static int get()
{
return someConstant;
}
private:
friend int main(); // this should probably not be `main` in real code
static void set(int value)
{
someConstant = value;
}
static int someConstant = 0;
};
In main:
int main()
{
SomeConstant::set(123);
}
Anywhere else:
void f()
{
int i = SomeConstant::get();
}
You can further hide the class with some syntactic sugar:
int someConstant()
{
return SomeConstant::get();
}
// ...
void f()
{
int i = someConstant();
}
Finally, add some error checking to make sure you notice if you try to access the value before it is set:
class SomeConstant
{
public:
static int get()
{
assert(valueSet);
return someConstant;
}
private:
friend int main(); // this should probably not be `main` in real code
static void set(int value)
{
someConstant = value;
valueSet = true;
}
static bool valueSet = false;
static int someConstant = 0;
};
As far as your edit is concerned:
Nothing of this has anything to do with "OO". Object-oriented programming is about virtual functions, and I don't see how your problem is related to virtual functions.
char * - means ur creating a pointer to char datatype.
int - on other hand creates a variable. u cant declare a const variable without value so i suggest u create a int * and use it in place of int. and if u are passing it into functions make it as const
eg: int *myconstant=&xyz;
....
my_function(myconstant);
}
//function decleration
void my_function(const int* myconst)
{
....
}
const qualifier means variable must initialized in declaration point. If you are trying to change her value at runtime, you get UB.
Well, the use of const in C++ is for the compiler to know the value of a variable at compile time, so that it can perform value substitution(much like #define but much more better) whenever it encounters the variable. So you must always assign a value to a const when u define it, except when you are making an explicit declaration using extern. You can use a local int to receive the real value at run time and then you can define and initialize a const int with that local int value.
int l_int;
cout<<"Enter an int";
cin>>l_int;
const int constNum = l_int;

How do I define static array in .cpp file of my class

I know there is many question talks about static function and variable but I can't find the one that explain me how do things like this:
board.h
class board:public QGraphicsPixmapItem
{
public:
board();
static basedice *gamepos[8][8];
};
and I want to defined my array like this:
board.cpp
board::board()
{
for (int i=0;i<8;i++)
{
for (int j=0;j<8;j++)
{
gamepos[i][j]=NULL;
}
}
}
And I have one more question,Is that a right way to use an array in many classes something like global array... for example in chess game for holding postion of my pieces?
Sorry for my bad english.
If you really want the gamepos array to be static you can declare a static method in class Board that will initialize the array.
Then you call this method from outside the class.
int main() {
Board * myboard = new Board();
Board::initGamepos();
}
However looking at your code and what you want to do (which is reinitialize the gamepos array everytime you create a new Board instance, it is clear that you do NOT want gamepos to be static.
1 board <=> 1 gamepos array : that is not the mark of a static member, that is the mark of a standard member.
Static variables are automatically initialized to zero/false/null, so you don't need to initialize the array.
Anyway, you should not be reinitializing a static variable from your instance constructor as that will produce funny results.

Restart a game and reinstantiate a global object [duplicate]

This question already has an answer here:
Restarting a game and reinstantiate objects
(1 answer)
Closed 9 years ago.
This is a very similar problem to a question i have already looked at, answered here - Restarting a game and reinstantiate objects .
I want exactly the same thing except my problem is slightly different in that the object i wish to reinstantiate is 'global' and is only ever created when the program first runs.
At present i create the new 'Player' after my #includes and before my function prototypes ...
#include "Player.h"
#include "Monster.h"
using namespace std;
string MonsterTypes[3] = {"Orc","Goblin","Dark Rider"};
//create a stack of 'monsters'
stack<Monster>MonsterList;
Player* NewPlayer = new Player();
int NewGame();
void SetupPlayer();
void SetupMonsters();
void MainGame();
void Combat();
int GetMonstersLeft();
Do i need to create an entire factory class just to create a single player? Obviously when i call the function 'setupPlayer' i could create the player object in there, but would i not then have to pass 'NewPlayer' to every other function, i was just wandering if there was a way to avoid doing that?
You can create a new player in SetupPlayer, and assign it to NewPlayer.
Since your global NewPlayer is a pointer to a Player object, you can simply create a new Player in its place every time you call SetupPlayer(), as follows:
Player* NewPlayer = NULL; // Initialized when calling SetupPlayer()
void SetupPlayer() {
delete NewPlayer; // Delete the previous player (if any)
NewPlayer = new Player();
}
You don't really need dynamic allocation. You can just declare an automatic variable like this:
Player player;
and then when you want to reset it you can use:
player = Player();
Always remember that dynamic allocation is expensive.
What I would probably do, instead, is to create a "factory" function:
Player make_player() {
Player ret;
// setup ret
return ret;
}
So that you can get rid of that global object. Don't worry about the performance of copying the object back when returning: copies are elided by a well-known optimization (return value optimization - RVO).

access violation reading location 0x000000004

I am doing a C++ coding practice in Visual Studio and keep having this problem shown as title. I know where the problem happens but I don't why it happens and how to solve it. Please help me with this.
class_templete.h
typedef std::string QuestionName;
class ClassTemplete
{
public:
ClassTemplete(Question iQuestionName);
private
static std::map<QuestionName,ClassTemplete *> questionName_questionPointer_map_;
}
class_templete.cpp
map<QuestionName, ClassTemplete *> ClassTemplete::questionName_questionPointer_map_;
ClassTemplete::ClassTemplete(QuestionName iQuestionName)
{
ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this;
}
chapter1_question1.h
class C1Q1 : public ClassTemplete
{
public:
C1Q1(QuestionName iQuestionName) : ClassTemplete(iQuestionName) {};
private:
static QuestionName question_name_;
static C1Q1 question_instance_;
}
chapter1_question1.cpp
QuestionName C1Q1::question_name_ = "C1Q1";
C1Q1 C1Q1::question_instance_(C1Q1::question_name_);
I found out that problem happens at this place when I run the program:
ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this;
However, I cannot explain why it happens.
Please feel free to contact me if more information is required.
Kind regards,
Yi Ji
Where is QuestionName C1Q1:::question_name_ located relative to ClassTemplate::questionName_questionPointer_map_? They seem to be both variables with static storage duration, i.e., they are constructed before main() is run. However, the C++ compiler/linker orders the construction of such global objects only with one translation unit (in which case the objects are constructed top to bottom), not between translation units (in which case the objects are constructed in a random order).
You problem looks as if ClassTemplate::questionName_questionPointer_map would be constructed after C1Q1::question_name_. That is, when C1Q1::question_name_ is constructed, an object which is not, yet, constructed is being accessed.
The conventional fix is to make the static object other objects depend on not an object but rather a function with a local static variable to which a reference is returned:
std::map<QuestionName,ClassTemplete *>&
ClassTemplete::questionName_questionPointer_map_() {
static std::map<QuestionName,ClassTemplete *> rc;
return rc;
}
(note that this construction is not thread-safe when you don't use C++11; it is thread-safe when using C++11).
You have to use std::map::insert, you can't do ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this; when you insert a new key in the map.
This code should work:
ClassTemplete::questionName_questionPointer_map_.insert(std::make_pair(iQuestionName, this));

std::vector::push_back fails to add data to my vector

I have these two pieces of code that are messing up without throwing any errors:
The first piece is from a custom class which I am trying to push into an array.
class idRect {
public:
sf::FloatRect rect;
int id;
idRect(int _id, sf::FloatRect _rect) : id(_id), rect(_rect) {}
};
The second piece is where the function gets called.
if((deltaX + deltaY) < 500) { //Taxi distance calculation
cout << endl << "Passed check" << endl;
gloAreas.push_back(idRect(id, entity.getGlobalBounds()));
}
gloAreas is a globally defined vector which contains idRect objects.
As said earlier I have observed from the console that "Passed check" outputs and that the size of my vector doesn't increase EDIT: globally.
Edit: The error also seems rather random and only happens for 1 in 6 instances of the objects calling the push_back functions.
I'm using SFML for the sf::FloatRect which is basically just a vector of 4 floats. getGlobalBounds() is another function from SFML that returns the bounding rectangle of a sprite in sf::FloatRect format.
Any ideas of what is going wrong?
Sincerely,
BarrensZeppelin
EDIT 2:
The error seems to have erupted due to a mix between my own incompetence and std::multiset's sorting, maybe I'll come back for that in another thread ^^ (With a sscce ofc)
Thank you guys for you time and help.
If gloAreas is defined as static, it won't be a true global. It will have global scope, but a copy of it will be created for each translation unit.
For a global, you need to declare it with extern and define it in a single implementation file.
Disclaimer: answer is just a guess, my crystal ball might be off today...
My crystal ball answer: You have redefined gloAreas in an interior scope, like this:
vector<idRect> gloAreas; // defines global
void F( vector<idRect> gloAreas ) // defines local instance
{
gloAreas.push_back(); // affects local instance
return; // destroys local instance
}
int main() {
F(gloAreas); // Copies global instance to parameter
// global remains unchanged.
}