Passing a pointer to enum to a function - c++

I'm trying to pass an enum declared outside of a function's scope, to a function, so that changing the value of the enum within the function changes the value of the enum pointed to. Using the enum itself just in the scope of the object is not an option as I wish to use this function with multiple different instances of this enum.
I have an enum 'ColourState'. Declared like so. and a pointer to a ColourState.
enum ColourState {COLOUR1, COLOUR2};
ColourState* CS_GO_score;
The pointer was initialised like so.
CS_GO_score = new ColourState;
*CS_GO_score = ColourState::COLOUR2;
I'm now trying to pass the ColourState pointed to by CSS_GO_score to the function 'pulsateColour'
Like so.
void HUD::pulsateColour(GLfloat *colour1, GLfloat *colour2, GLfloat *objectCol, ColourState goingTo, int timeInFrames)
{
GLfloat difference[4];
//give us an array of values to change the array by in the alloted time
difference[0] = (colour1[0]-colour2[0])/timeInFrames;
difference[1] = (colour1[1]-colour2[1])/timeInFrames;
difference[2] = (colour1[2]-colour2[2])/timeInFrames;
difference[3] = (colour1[3]-colour2[3])/timeInFrames;
//depending on the state, transform the array in one direction or another
if(goingTo == ColourState::COLOUR2)//if we're moving toward colour 2
{
for(int i = 0; i<4; i++)
{
objectCol[i] -= difference[i];//subract the difference till we get there
//we need to SNAP to the colour as we will not hit it every time using floats
if( (objectCol[i]>(colour2[i]-(difference[i]*2))) && (objectCol[i]<(colour2[i]+(difference[i]*2))) )
{//if we hit this tiny but huuuge target
objectCol[i] = colour2[i];//SNAP
}
}
}else{
if(goingTo == ColourState::COLOUR1)
{
for(int i = 0; i<4; i++)
{
objectCol[i] += difference[i];//add the difference till we get there
//we need to SNAP to the colour as we will not hit it every time using floats
if( (objectCol[i]>(colour1[i]-(difference[i]*2))) || (objectCol[i]<(colour1[i]+(difference[i]*2))) )
{//if we hit this tiny but huuuge target
objectCol[i] = colour1[i];//SNAP
}
}
}
}
if((objectCol[0] == colour1[0])&&(objectCol[1] == colour1[1])&&(objectCol[2] == colour1[2])&&(objectCol[3] == colour1[3]))
{//if the objcolour == colour 1
goingTo = ColourState::COLOUR2;//it's now time to move towards colour 2
}else{
if((objectCol[0] == colour2[0])&&(objectCol[1] == colour2[1])&&(objectCol[2] == colour2[2])&&(objectCol[3] == colour2[3]))
{//if the objcolour == colour 2
goingTo = ColourState::COLOUR1;//it's now time to move towards colour1
}
}
}
}
This function is called like so.
pulsateColour(white,blue, GO_scoreColour, *CS_GO_score, 10);
However, when the value pointer to by 'goingTo' and 'CS_GO_score' (they should be the same address therefore technically the same object right?), watching the values monitor in VS i see that only the value pointed to by 'goingTo' (as it is local to the function) is changed? What am I doing wrong?

You are passing the enum by value, so the function has a local copy of whatever you pass it. If you want to pass an enum and modify it value, I suggest passing by reference.
enum ColourState {COLOUR1, COLOUR2};
void change_colour(ColourState& c)
{
c = COLOUR2;
}
....
ColourState cs = COLOUR1;
change_colour(cs);

However, when the value pointer to by 'goingTo' and 'CS_GO_score'
(they should be the same address therefore technically the same object
right?),
NO...
It will be the "same object" if you pass the pointer itself. Here you are passing the value pointed by the pointer. Alternatively you may want to pass a reference.
void HUD::pulsateColour(GLfloat *colour1,
GLfloat *colour2,
GLfloat *objectCol,
ColourState goingTo, /* pass by value */
int timeInFrames)
...
I'm trying to pass an enum declared outside of a function's scope, to
a function, so that changing the value of the enum within the function
changes the value of the enum pointed to.
You will need to change the funcion to take a pointer or a reference:
ColourState *goingTo, /* pass direct the pointer */
or
ColourState &goingTo, /* pass a reference-dont need to change the body of the function */

Related

I want return type pointer but i want my function to return pointer of derive class

Dragon* Dragon::spawn() {
int x = rand() % 5;
int y;
if (!if_locked(x)) //is a function to see if that id is unlocked because i want some dragon to be generated only if you have certain xp so it will call func again until unlocked id is generated
spawn();
else
y = unlocking(m); // Y is generated form 1-5, I have assigned Id to each derive class whosoever id matches Y that pointer will be returned
if (y == 1) {
GroundDragon* pt;
return pt;
}
if (y == 2) {
WaterDragon* st;
return st;
}
if (y == 3) {
IceDragon*bt;
return bt;
}
if (y == 4) {
FireDragon* ct;
return ct;
}
if (y == 5) {
DarkDragon* dark;
return dark;
}
}
As you can see im making syntax mistakes i hope someone can guide me
The return type of function is base class and all the classes in if statement are derive class
so i can later use this function
template<class T>
void spawner(T*) {// I will spawn() fucntion as perimeter at time of call
T = new T;
}
Forgive me if im repaeting question the last time i post it didnt get attention i was expecting so i modifed my code a bit hopeful it is clear now`
int Dragon::unlocking(Mage m) {
if (m.getxp() <= 50 and m.getxp() <= 100) {
unlock[0] = 1;
cout << "Congratulation GroundDragon unlocked " << endl;
return 1;
}
if (m.getxp() > 100 and m.getxp() < 150) {
unlock[1] = 1;
cout << "Congratulation WaterDragon unlocked " << endl;
return 2;
}
if (m.getxp() > 150 and m.getxp() < 175) {
unlock[2] = 1;
cout << "Congratulation IceDragon unlocked " << endl;
return 3;
}
if (m.getxp() > 175 and m.getxp() < 500) {
unlock[3] = 1;
cout << "Congratulation FireDragon unlocked " << endl;
return 4;
}
if (m.getxp() > 500) {
unlock[4] = 1;
cout << "Congratulation DarkDragon unlocked " << endl;
return 5;
}
}
bool Dragon::if_locked(int x) {
if (unlock[x] == 1) {
return true;
}
else
return false;
}
*Im not comfortable with smartpointer(i have never used them before but i would love to use them if you show me how to call it main *
I used raw pointer but it is still showing me errors please help mw
The idea is sound, it's just the execution that failed.
If you want to have a factory function that will return different objects that will then behave polymorphically, this is perfectly fine, with one important thing - you need to return actual objects.
Your factory function has a return type of Dragon*. This means that whatever value you return, it will be a pointer pointing to (some sort of a) Dragon. However, the value of that pointer can point to an object that is actually an instace of FireDragon, IceDragon etc. When you create an instance of such an object, the pointer to such instance can then get converted to the appropriate return type and returned.
In your case though, while you're creating temporary objects of type pointer-to-some-sort-of-dragon, you're not actually filling them with instances. They all are created with an unspecified value, and that value is then converted to an unspecified value of type Dragon*, with no way to extract the information which type it was converted from.
So, in order to make it work in a usual fashion, we just need to create a new instance of appropriate type and return it. We don't ever want to return raw pointers from functions when transferring ownership, so std::unique_ptr is a much better alternative:
std::unique_ptr<Dragon> Dragon::spawn() {
int x = rand() % 5;
/* note - this bit of code doesn't make any sense whatsoever
int y;
if (!if_locked(x)) //is a different function
spawn();
else
y = unlocking(m); //is also a different function
*/
// note that `rand() % 5` will produce values 0 through 4.
switch(x) {
case 0: return std::make_unique<GroundDragon>();
case 1: return std::make_unique<WaterDragon>();
case 2: return std::make_unique<IceDragon>();
case 3: return std::make_unique<FireDragon>();
case 4: return std::make_unique<DarkDragon>();
}
}
Now you don't need the spawner function at all; you can directly use the returned value.
I think the first important lesson to give is about initializing pointers.
The line
GroundDragon* pt;
declares that there is a pointer to a GroundDragon object, so far so good. However, this does not create an object.
As an analogy: you created a direction sign that is able to point into the direction of a village, but you do not build an actual village for it to point towards. And right now, it just points into some random direction.
Being uninitialized, pt contains a random value, not the address of an existing object of type GroundDragon. Doing anything with it will most likely result in bad things (it is undefined behaviour in particular).
In order to initialize it, you would write it like
GroundDragon* pt = new GroundDragon;
This creates an objects of type GroundDragon on the heap and assigns it's address to pt.
Also note that every new needs a delete to keep the memory clean, just to mention this preemptively.
This is very essential knowledge - make sure to understand this.
I wanted to write this in order to show you how to work with raw pointers, as an addition to the answer of Bartek Banachewicz, who did not show the way to initialize raw pointers. What he then does, using smart pointers, is clearly a way better approach than using raw pointers, though. However, I'd say that it is quite important that you are also able to work with raw pointers. Make sure to be able to do both in the long run, and use smart pointers whenever you can.
Edit: Now for the other part of your code,
int x = rand() % 5;
int y;
if (!if_locked(x)) //is a function to see if that id is unlocked because i want some dragon to be generated only if you have certain xp so it will call func again until unlocked id is generated
spawn();
else
y = unlocking(m);
First of all, please be aware that calling spawn(); ignores the return value. Which means, it has no effect at all. What you probably wanted to write is return spawn();.
Second, if(!if_locked(x)) seems to me to be the contrary of what it should be. "if not locked" means "if unlocked", and in that case, it should not try it again but instead proceed, right?
And, is the Mage m that you give to unlocking a member of Dragon? Sounds like it rather should be a pointer, if you don't especially want a relationship like Dragon owns Mage.
In any case, I would keep unlocking out of spawn. A method like spawn says that it is good for spawning. Especially printing that something is unlocked is not something I would intuitively understand a part of the spawning process. Also, I would name it differently, as "unlocking" is a status rather than a command. Go like check_for_new_unlocks or something like that, which sounds like a command. And do it separately from spawn.
Also, note that you check for narrow experience intervals - are you sure that it can't happen that an interval is never triggered, as the character might advance over the interval with never calling the method in between?
Furthermore, I'd call the array that says if something is unlocked differently. "unlock" sounds like a command. How about "available"?
Also, I find the recursive call of spawn to be less readable as trying out other values for x, but that is opinion. I'd go like
int x = rand() % 5;
while(not available[x])
{
x = rand() % 5;
}
Maybe this can be done more clever, though, based on the actual mechanics. You could create the random variable like int x = rand() % total_available(); for instance.
Note that a lot of this is somewhat opinion based. In this regard, I want to point you towards CodeReview - as soon as your code works correctly, you might want to post it there for people to help you improve it in several different regards.

c++ 2d array of class pointers

i am trying to create a 2d array holding pointers of my class. first, i'd like to assign all of them NULL:
Timetable::Timetable(int hours) : TimetableBase(hours){
scheduledLectures = new Lecture**[5];
for (int i = 0; i < 5; i++) {
scheduledLectures[i] = new Lecture*[hours];
for (int j = 0; j < hours; j++)
scheduledLectures[i][j] = NULL;
};
}
this is for a timetable generator application. i have a function to set these pointers to a specific object.
void Timetable::setLecture(Lecture& lecture){
while ((lecture.getDuration()) -1 > 0){
scheduledLectures[lecture.getDayScheduled()][(lecture.getHourScheduled())+1] = &lecture;
}
}
the compiler returns no errors for this, but when its running, it seems that the pointers remain NULLs.
i am sure the error is inside the setter function (and almost sure that its a grammar mistake) but i cannot find the solution for that.
whats wrong in here?
thank you
Use a vector (or std::array) of pointers or shared_ptrs (or unique_ptrs depending on how your lifetimes are arranged) instead of a 2D array of pointers that you manage yourself. Save yourself the trouble of managing the memory and lifetimes of your objects manually.
class TimeTable {
vector<vector<shared_ptr<Lecture>>> scheduledLectures;
};
Timetable::Timetable(int hours)
: TimetableBase(hours),
scheduledLectures(5, vector<shared_ptr<Lecture>>(5)) {}
void Timetable::setLecture(std::shared_ptr<Lecture> lecture){
while ((lecture->getDuration()) -1 > 0) { // not sure what this does
scheduledLectures[lecture->getDayScheduled()][(lecture->getHourScheduled())+1] = lecture;
}
}
You can test whether a shared_ptr is null like follows
auto s_ptr = std::shared_ptr<int>{}; // null
// either assign it to a value or keep it null
if (s_ptr) {
// not null
}
If you are managing the memory of the Lecture objects elsewhere then just use a 2D vector of pointers and trust your code
class TimeTable {
vector<vector<Lecture*>> scheduledLectures;
};
Timetable::Timetable(int hours)
: TimetableBase(hours),
scheduledLectures(5, vector<Lecture*>(5)) {}
void Timetable::setLecture(Lecture& lecture){
while ((lecture.getDuration()) -1 > 0) { // not sure what this does
scheduledLectures[lecture.getDayScheduled()][(lecture.getHourScheduled())+1] = &lecture;
}
}

Array keeps returning only the last element. [C/Arduino]

i've a problem with an array (called "Inputs" of type "GeneralInput") on Arduino,basically,no matter which element i try to have access to,the code always returns me the last element of that array.
Here's part of the code:
//...include statements
//other initializations
GeneralInput *Inputs[19];
void setup()
{
//...
//...
InitializeInputs();
}
void InitializeInputs()
{
//type 0 = pedal switch; 1 = volume pedal
//type 2 = potentiometer; 3= switch;
//pedal switches
Inputs[0] = &GeneralInput(0,0,true,false,NULL,10);
Inputs[1] = &GeneralInput(1,0,true,false,NULL,9);
Inputs[2] = &GeneralInput(2,0,true,false,NULL,6);
Inputs[3] = &GeneralInput(3,0,true,false,NULL,5);
//volume pedal
Inputs[4] = &GeneralInput(4,1,false,false,NULL,A2);
//potentiometer
Inputs[5] = &GeneralInput(5,2,false,true,mux2,5);
Inputs[6] = &GeneralInput(6,2,false,true,mux2,6);
Inputs[7] = &GeneralInput(7,2,false,true,mux2,7);
Inputs[8] = &GeneralInput(8,2,false,true,mux2,8);
Inputs[9] = &GeneralInput(9,2,false,true,mux2,9);
Inputs[10] = &GeneralInput(10,2,false,true,mux2,10);
Inputs[11] = &GeneralInput(11,2,false,true,mux2,11);
//switch
Inputs[12] = &GeneralInput(12,3,true,true,mux2,15);
Inputs[13] = &GeneralInput(13,3,true,true,mux2,14);
Inputs[14] = &GeneralInput(14,3,true,true,mux2,13);
Inputs[15] = &GeneralInput(15,3,true,true,mux2,12);
//joystick
Inputs[16] = &GeneralInput(16,3,true,true,mux1,2); //switch
Inputs[17] = &GeneralInput(17,2,false,true,mux1,1); //x axis
Inputs[18] = &GeneralInput(18,2,false,true,mux1,3); //y axis
}
void loop()
{
int length=0;
//cycle through different inputs
int startIndex=0,endIndex=0;
//temp arrays
byte toSendTmp[30];
for(int i=0;i<30;i++)
toSendTmp[i]=0;
//...
//..
int packetIndex=0;
for(int i=startIndex;i<endIndex;i++)
{
//if the input is updated,fill the array with the new data
/*
* When i try to have access to the i-element i always get
* the last one instead.
*/
if(Inputs[i]->Update())
{
toSendTmp[(packetIndex*3)] = Inputs[i]->GetID();
toSendTmp[(packetIndex*3)+1] = Inputs[i]->GetType();
toSendTmp[(packetIndex*3)+2] = Inputs[i]->GetValue();
packetIndex++;
}
}
//....
//...
}
And if needed here's the GeneralInput.h and GeneralInput.cpp code.
NOTE: I can't tell if the array is always returning the last item or if every slot of the array is filled with a pointer to the same object (the last created).
Any idea on what i'm doing wrong?
Thanks in advance.
Your &GeneralInput are incorrect, in fact you create temporary objects and store their adresses in an array, but as soon as your GeneralInput object get destroy (same line as creation), a new object takes place at the same address:
// Create GeneralInput at address #
Inputs[0] = &GeneralInput(0,0,true,false,NULL,10);
// End of your temporary object, the `GeneralInput` object is destroyed but you still
// points to its address...
/* etc. */
You're getting the last value because the compiler always create the GeneralInput at the same address, so all Inputs[] point to the same address.
You need to dynamically create your GeneralInput:
Inputs[0] = new GeneralInput(0,0,true,false,NULL,10);
Every slot in the array has a pointer to the same memory location which is the occupied by the last element you create. By doing &GeneralInput(...) you are creating a GeneralInput object on the stack and retrieving its stack address. But since the GeneralInput object itself is never assigned to a variable, the memory it occupies is immediately available for reuse. This means that every GeneralInput object is created at the same address on the stack. The solution, however, isn't to change your code to something like
GeneralInput genInput = GeneralInput(...);
Inputs[...] = &genInput;
Code like that will still be filling your array with pointers to stack addresses. Those pointers will immediately become invalid when the function returns. You should be filling your array with something like
Inputs[...] = (GeneralInput*)malloc(sizeof(GeneralInput));
*Inputs[...] = GeneralInput(...);
Using this method make sure that if your Inputs array ever reaches a point where you don't use it anymore loop over it freeing every element.
Edit: Arduino using C, so doesn't have new. Use malloc and free instead.
As others have said, the problem is with the address of the temporary variables. You can get around the "new" problem by having default parameters.
class GeneralInput
{
public:
GeneralInput(int a = 0, int b = 0, bool c = true, bool d = true, int* e = NULL, int f = 0);
...
};
Then declare your array - this takes GeneralInput with the default parameters
GeneralInput inputs[20];
Then in Initialize - then you won't have the new problem or the problem of temporaries disappearing at the end of the routine.
void InitializeInputs()
{
inputs[0] = GeneralInput(0,0,true,false,NULL,10);
...
}
I don't know what the NULL points to but you might want to put in a copy operator for this if it is anything else other than copying the value. Not very efficient because it calls the constructor twice but that only happens at initialization.

Why does the content of a pointer change?

I'm a C# programmer and now using C++ to do some work.
pair<Point,double>* p=NULL;
Sphere* sphere=NULL;
for (int i=0;i<spheres.size();i++)
{
vector<pair<Point,double>> solution=findIntersection(Point(ray.origin),Point(ray.direction.x,ray.direction.y,ray.direction.z),spheres[i]);
if(solution.size()==0)
continue;
if(p==NULL || solution[0].second<p->second)
{
p=&solution[0];
sphere=&spheres[i];
}
}
if(p==NULL)
return backgroundColor;
else
{
Color c=localIlluminate(p->first,*sphere);
return c;
}
I want p.first to have the smallest value, and sphere be the cooresponding sphere that is used to get p.
After debugging, I find the code doesn't work. In the first loop, p will be assigned the address of solution[0], assuming the value is {(0,0),0}. Then the loop continues and when i=1, assume solution[0] becomes {(1,2),3} and value of p also becomes {(1,2),3}.
I don't expect the value of p to change. How should I fix it?
You are storing the reference to a local variable outside the scope in which the local variable is declared.
Every iteration solution is not valid anymore, then the address to it shouldn't be considered valid. To obtain what you need you should assign the variable by value, so that you actually copy the contained value, eg:
pair<Point, double> p = std::make_pair(whatever, std::numeric_limits<double>::max());
for (...)
{
if (solution[0].second < p.second)
p = solution[0];
}
The fact that the address changes can be caused by multiple reasons, but you shouldn't bother understanding why, just avoid this kind of situation. Your misconception comes from the fact that C# has a garbage collection which prevents solution[0] from becoming invalid, which is not true for C++, when variable are declared on stack.
When you assign to p it points to the adresss of &solution[0] but on the next iteration of the loop that variable goes poof and a new one gets created and p points to either random stuff or something else.
It might be better to just store a copy in p, so make p a regular variable and copy over the solution[0] by assigning. You can have another bool variable to determine if a solution was found.
pair<Point,double> p;
Sphere sphere;
bool solutionFound = false;
for (int i=0;i<spheres.size();i++)
{
vector<pair<Point,double>> solution=findIntersection(Point(ray.origin),Point(ray.direction.x,ray.direction.y,ray.direction.z),spheres[i]);
if(solution.size()==0)
continue;
if(!solutionFound || solution[0].second < p.second)
{
p=solution[0];
sphere=spheres[i];
solutionFound = true;
}
}
if(!solutionFound)
return backgroundColor;
else
{
Color c=localIlluminate(p.first, sphere);
return c;
}

Pointer value resets to null shortly after assignment

I have a pointer that is set to 0, then later on in the same function, inside some loops/conditions I try to re assign it.. (please read the comments)
for(Entity* tile : _originalFloorTiles)
{
for(Turns turn : pointsUpLeftDownRight)
{
if(tile->GetCollisionRect().ContainsPoint(turn.first.x, turn.first.y)){
turn.second = tile; //everything looks fine here, turn.second is still null and tile is a valid pointer
assert(turn.second); //turn.second is definitely assigned the value of tile here.
}
HAPI->DebugText("check pointsUpLeftDownRight now");//!Here's where it gets weird,
// If i hover over turn and inspect it in visual studio now, turn.second is still completely valid
// (with the assigned value of tile).
// But hovering over pointsUpLeftDownRight shows its contents for each turn..
// and inside there the current turn is a NULL pointer for turn.second!
}
}
So one moment i have assignd my pointer no problem, and the next moment the pointer doesn't seem to have changed at all.
To clarify, Turns is a lazy typedef for std::pair<Vect, Entity*> , apologies if that makes my code harder to read, it's some quickly thrown together enemy ai. I'll post the complete function below.
I'm really stumped here and not sure if i'm being an idiot or something weird is going on, would really appreciate anyone taking the time to look.
//looks for turns that the ghost can take.
void IceGhostNPC::RespondToTimePassed()
{
//Entity* t = _originalFloorTiles[0];
//test if enough time has passed since ghost last decided to look for turns
if(_lastTimeTurned < timeGetTime() - _timeBeforeSearchingForTurns)
{
//store points surrounding ghost in a way that we can associate them with a valid floor tile to move onto
std::vector<Turns> pointsUpLeftDownRight;
pointsUpLeftDownRight.push_back(
Turns(Vect(GetCenterXPos(), GetCenterYPos() - floorTileHeight), 0)); //point above
pointsUpLeftDownRight.push_back(
Turns(Vect(GetCenterXPos() - floorTileWidth, GetCenterYPos()), 0)); //point left
pointsUpLeftDownRight.push_back(
Turns(Vect(GetCenterXPos(), GetCenterYPos() + floorTileHeight), 0)); //point down
pointsUpLeftDownRight.push_back(
Turns(Vect(GetCenterXPos() + floorTileWidth, GetCenterYPos()), 0)); //point right
//look through original floor tiles,
for(Entity* tile : _originalFloorTiles)
{
//see if its possible to take a turn
for(Turns turn : pointsUpLeftDownRight)
{
if(tile->GetCollisionRect().ContainsPoint(turn.first.x, turn.first.y)){
turn.second = tile;
assert(turn.second);
}
HAPI->DebugText("check pointsUpLeftDownRight now");
}
}
//Now to make the behaviour more interesting we have the ghost randomly take one of the turns,
// ( we use associated tile to check the turn is possible, and we can also change that tile to an icy patch )
bool turnTaken = false;
do{
int turnChoice = rand() % 4;
if(pointsUpLeftDownRight[turnChoice].second == 0)
continue; //go back to top of loop if that turn had a null tile
else
{
switch(turnChoice){
case 0: //turn upwards
_moveable->SetYDirection(Controller::UP);
_moveable->SetXDirection(Controller::NONE);
break;
case 1: //turn leftwards
_moveable->SetYDirection(Controller::NONE);
_moveable->SetXDirection(Controller::LEFT);
break;
case 2: //turn downwards
_moveable->SetYDirection(Controller::DOWN);
_moveable->SetXDirection(Controller::NONE);
break;
case 3: //turn right
_moveable->SetYDirection(Controller::NONE);
_moveable->SetXDirection(Controller::RIGHT);
break;
}
turnTaken = true;
_lastTimeTurned = timeGetTime();
//ice tile up baby
}
}while(turnTaken = false);
}
FinishResponding(timeGetTime());
}
Check this line:
for(Turns turn : pointsUpLeftDownRight)
You are iterating over copies of the elements in pointsUpLeftDownRight. Whatever value you assign to that copy will be lost when the copy is destroyed (at the end of the for body). Your assignment changes a temporary.
Try with this instead:
for(Turns& turn : pointsUpLeftDownRight)