C++ Empty Pointer - c++

So I am new to C++ and I am trying to use an inner class like this:
struct PreviousButton {
SelectionScreen* ss;
PreviousButton(SelectionScreen* sss) {
ss = sss;
}
void ClickAction() {
//images is a vector with images. in here it is empty
ss->images;
}
};
This inner class is inside the class SelectionScreen and I need to perform a click action and need some of the variables of the selectionscreen.
SelectionScreen:
class SelectionScreen {
public:
void AddImage(Image img);
std::vector<Image> images;
How I fill the vector:
Image* image = new Image{ };
AddImage(*image2);
AddImage method:
void SelectionScreen::AddImage(Image img)
{
images.push_back(img);
}
But when I try to use the selectionscreen inside the class all of the variables are empty. But when I look into selectionscreen all of the variables are set.
The way I pass the SelectionScreen:
PreviousButton* previousButton = new PreviousButton(*ren, this);
How SelectionScreen gets initialized: (this method is called from the main)
int Program::Render() {
bool quit = false;
MenuScreen m = SelectionScreen{ Sdl_Renderer };
// change current screen to selectionscreen
ScreenController::GetInstance().ChangeMenu(m);
while (!quit) {
// handle user input and repaint
}
// delete all windows if quit is true
SDL_DestroyRenderer(Sdl_Renderer);
SDL_DestroyWindow(Sdl_Window);
SDL_Quit();
return 0;
}
Does anyone knows why my variables are empty?

This isn't addressing the immediate issue you describe, but you have a serious problem here:
ss->currentImageIndex = ss->images.capacity() - 1;
images.capacity() - 1 is not guaranteed to return a valid index into your vector. You should use images.size() - 1.
std::vector::capacity() tells you the storage space currently allocated for the vector, not the number of elements it actually contains.
UPDATE
When you assign a SelectionScreen to a MenuScreen like this
MenuScreen m = SelectionScreen{ Sdl_Renderer };
you "slice" the SelectionScreen object (see What is object slicing?).
This line creates a new MenuScreen object, m, by copy-constructing it from a temporary SelectionScreen object. The new MenuScreen object, m, is not a SelectionScreen. It is also a completely distinct object from the temporary SelectionScreen created on the right-hand side of this expression.
Your PreviousButton, which I assume is created in the constructor of SelectionScreen, holds a pointer to the temporary SelectionScreen, which the compiler is free to delete once this line has completed.
To fix this, you could use this initialisation instead:
MenuScreen& m = SelectionScreen{ Sdl_Renderer };
In this case, m is a reference to your (temporary) SelectionScreen - this is good because (a) references are polymorphic, so it still knows that it's really a SelectionScreen, not just a MenuScreen and (b) it's a reference to the exact same SelectionScreen object created on the right-hand side, which your PreviousButton has a pointer to. I've also bracketed the "temporary" bit now, because taking a local reference to a temporary guarantees it will exist for as long as the reference does (see e.g. Does a const reference prolong the life of a temporary?).
Note that I am assuming here that you only make use of this SelectionScreen within the while (!quit) loop that follows, i.e. the screen can safely be deleted at the end of this int Program::Render() method.

Related

"The value is never used" pointer re-assignment C++

I'm refactoring this bit of code:
struct GameState {
PieceState piece;
}
//create local copy from piece, modify it, and only when its VALID copy it back!
void update_game_play(GameState *game, const InputState *input) {
PieceState piece = game->piece;
//'left' from perspective of the game
if (input->dleft > 0) {
--piece.offset_col;
}
if (is_piece_valid(&piece, game->board, WIDTH, HEIGHT)) {
game->piece = piece;
}
}
This code takes a piece struct, and only when it's valid it's re-assigned to the GameState struct.
But in my refactored code the assignment gives me a warning that the value is never used in the last line, inside the if-statement:
//create local copy from piece, modify it, and only when its VALID copy it back!
void update(Piece *pieceTmp, Board *board) override
{
auto piece = *pieceTmp;
//'left' from perspective of the game
if (input.dleft > 0) {
--piece.offset_col;
}
//test with dummy if statement
if (true) {
pieceTmp = &piece; //"the value is never used"
}
}
The way I understood it, is that I'm dereferencing the pointer to a object, changing the object properties, and then assign the address of the object to my original pointer? What's going on?
The function accepts the first argument by value.
void update(Piece *pieceTmp, Board *board) override
That is it deals with a copy of the value of the original argument.
So the new value of the pointer
pieceTmp = &piece;
is used nowhere in the function (and in the caller).
Another problem is that you are trying to assign the address of a local variable that will not be alive after exiting the function. So after exiting the function the pointer (if it will be passed by reference) will have an invalid value.
Instead of this statement
pieceTmp = &piece;
you could write for example
*pieceTmp = piece;

Accessing a protected member

I'm new to C++ and struggling to setup a proper class with private members and accessing them. Basically, I have a vector of Layers which make up a Stack. I'd like to create a simple function which simply adds a layer to the stack. I've tried to simplify this example to explain my problem.
// Stack.h
namespace NS {
class Stack
{
public:
Stack() {
}
virtual ~Stack() {
}
std::vector<Layer> const &getLayers() const;
virtual Layer* AddLayer(TextureBase texture);
protected:
std::vector<Layer> _layers;
}
This is my cpp file
//Stack.cpp
namespace NS {
std::vector<Layer> const &Stack::getLayers() const {
return _layers;
}
Layer* Stack::AddLayer(TextureBase texture) {
Layer* newLayer = new Layer();
newLayer->setTexture(texture);
std::vector<Layer> layerStack = Stack::getLayers();
layerStack.push_back(*newLayer);
return newLayer;
}
}
In my main file I create the stack and then try to add the layer like this:
auto myStack = getStack();
myStack->AddLayer(myTexture);
However, when I place a breakpoint after this line, myStack doesn't contain any layers (the size is 0). I can step through the AddLayer function and it does appear to add the Layer to the Stack... but perhaps it's not referencing the vector correctly. Can anyone provide some guidance as to why this is occurring?
The problem is that layerStack is a local copy of _layers:
std::vector<Layer> layerStack = Stack::getLayers();
You are pushing your new layer to this local copy, not to your data member. You need to take a reference to your data member instead:
std::vector<Layer>& layerStack = Stack::getLayers();
Alas, this won't compile because your getLayers function returns a const reference. You need to add a non-const counterpart:
std::vector<Layer>& getLayers();
There are 3 issues you have to address.
1. Layer* newLayer = new Layer() will dynamically allocate a Layer object, but when you insert it into your vector, you dereference it, so you end up doing a push_back on a COPY of your Layer object. You could have just used Layer newLayer = Layer(), or if I understand your intent correctly a vector of Layer pointers:
vector<Layer*> _layers;
In order to be editable, your getLayers() function must NOT return a const-ref to the _layers vector. Change it to std::vector& getLayers();
Finally, std::vector layerStack = Stack::getLayers(); creates a COPY of the vector returned by getLayers(). Change it to std::vector& layerStack = Stack::getLayers()

calling a method to change a private variable in c++

I have 3 classes, Player, Monster and Attack.
Class Player
{
public:
void addMonster(string line);
// ...
}
Class Monster
{
public:
void addAttack();
// ...
private:
vector <Attack> _attacks;
}
Now, addMonster() creates a new monster mn, and then has mn call its method addAttack() to fill the vector _attacks
void Player::addMonster(string line){
//...
Monster mn(line); //creates a new monster
while(condition){
mn.addAttack();
}
}
void Monster::addAttack(){
//...
Attack *att = gio->findAttack(ID) //takes the attack from another part of the program
_attacks.push_back(*att);
}
and it seems to work, if I check the contents of _attacks while inside addAttack(), it is pushing the correct elements in, the size of _attacks changes and evreything,
but when the program returns to addMonster(), the _attacks vector of mn is still (or again) empty, as if it had not called the method at all.
Why?
it's as if the object that gets modified is just a copy of the one calling the method, so the original one is not affected, but then how am I supposed to change that vector of that specific object?
When you create the *att pointer in your addAtack you created it on the stack. Stack variables are deleted when their original function ends and so att is deleted at the and of add attack. One possible workaround for this is to create att on the heap, using the keyword new.

objects' variables get reset in vector (casting from void*)

Some background:
I am using Box2D in a game I'm making. It has a way of storing "user-data" to Box2D objects. This "user-data" takes a void*, so that it can be used for storing user-defined data. Now, when Box2D collisions happen, you can use this "user-data" to identify which objects have collided. Then you can cast the data to a class, and access the functions or variables of that class (and the particular instance of that class, if you have set the "user-data" as a reference to that instance). I have two sets of "user-data", one is a reference to a class instance and another to a struct so I can check the type of the objects.
This works good for objects that are not in a vector. I have tested this, and I can access the functions and variables(and modify them) of class instances without them being reset. But when I access my std::vector< Tile> objects by casting from void*, the variables I modify get reset immediately.
Relevant code:
I set the "user-data" like this:
tile->SetUserData(static_cast<Entity*>(this));
ball->SetUserData(static_cast<Entity*>(this));
bUserData* bud = new bUserData;
bud->entityType = BALL;
ballFixture.userData = bud;
bUserData* bud = new bUserData;
bud->entityType = TILE;
tileFixture.userData = bud;
MyContactListener class keeps track when the collisions start and end, this is also where the casting from void* to foo* happens:
MyContactListener.cpp
std::vector<Tile> solidTiles;
Ball ball;
// Called when two objects begin to touch.
void MyContactListener::BeginContact(b2Contact* contact) {
// Cast from void* to a struct, from which I can check the object type.
bUserData* budA = (bUserData*)contact->GetFixtureA()->GetUserData();
bUserData* budB = (bUserData*)contact->GetFixtureB()->GetUserData();
// Cast from void* UserData to Entity* (super-class of all the entities).
Entity* entityA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData();
Entity* entityB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData();
if((budA->entityType == TILE && budB->entityType == BALL)) {
Tile* tile = (Tile*)entityA; // Tiles are in std::vector<Tile>
Ball* ball = (Ball*)entityB; // Only one ball instance exists
// Modifying a tile instance variable, gets reset to the original value immediately!
tile->flaggedToErase = true;
// This works fine!
ball->setColorToBlue = true;
}
}
Question: How do I keep variables of the tile instances in vector from being reset to their original value?
Is it supposed to be a vector of Tile or Tile*? At a guess, I would suspect that this problem is due to using vector<Tile> which stores a copy of the object, as opposed to vector<Tile*> which stores a pointer to the object.
Compare this:
std::vector< Tile > tiles;
Tile t;
t.foo = 123;
tiles.push_back( t ); // a copy of t is put into the vector
t.foo = 456; // changes t, but not the copy in the vector
Tile t2 = tiles[0]; // makes yet another copy (t2.foo == 123)
... with this:
std::vector< Tile* > tiles;
Tile* t = new Tile;
t->foo = 123;
tiles.push_back( t ); // a pointer is put into the vector
t->foo = 456; // also changes in the vector because it's the same thing
Tile* t2 = tiles[0]; // still the same thing (t2->foo == 456)
If you want to have a vector of objects (not pointers) and change them inside the vector, you can do it like this:
std::vector< Tile > tiles;
Tile& t = tiles[0]; // note the ampersand, accesses by reference
t.foo = 456; // changes inside the vector
// I think you can also do this
tiles[0].foo = 456;
However, to do this you need to have the vector itself available, and you need to know which position the element you want to change is at. For your case, you don't know which position the element is at within the vector, so using vector<Tile*> is the simplest solution.

Unwanted creation of object at same memory address

I haven't been working with C++ for a long time and now I need to do some small "project".
I reviewed few topics trying to find solution for my problem with no results...
Here is "pseudo-code" (Pair is my class):
Pair** pairs;
I get size of table from input and create table of pointers:
pairs = new Pair*[size];
I have a loop which creates some object and puts it's reference into table of pointers. More or less:
while (...)
{
Pair pair(...); // calling constructor, creating object type of Pair.
pairs[i] = &pair;
i++;
}
The problem is that &pair is the same number everytime (every step of loop).
Let's say the address of first created object is 1234.
So with every step in loop it overrides this object at 1234. So each pointer in pairs points to the same address -> same object.
I would like to force creating this object at new place in memory.
I've been trying to put those objects into other table and then pass their reference to table of pointers:
Pair* clearPairs = new Pair[size];
while (...)
{
clearPairs[i] = Pair(...);
pairs[i] = &clearPairs[i];
i++;
}
But problem still occurs.
Any tips?, mistakes/errors in my code (or thinking)? Shall I implement some "copying constructor"?
while (...)
{
Pair pair(...); // calling constructor, creating object type of Pair.
pairs[i] = &pair;
i++;
}
pair is allocated with automatic storage duration and goes out of scope upon each iteration of the loop. You are saving a pointer to an invalid object (a bunch of them).
You should use a collection of smart pointers if you really need pointers (this is true when objects cannot be copied or copies are expensive), which may not be necessary at all. Try this instead:
vector<Pair> pairs;
// and if you need pointers...
vector<unique_ptr<Pair>> pairs;
while(whatever) {
pairs.push_back(Pair(...));
// or...
pairs.push_back(unique_ptr<Pair>(new Pair(...)));
}