Archived

This topic is now archived and is closed to further replies.

sanguineraven

STL vector problem

Recommended Posts

Ok so I''m working on Space Invaders using C++, SDL and STL. I have a "CSpriteBase" class which holds the base for a sprite (duh), which are its frames of animation, and the pauses between. So I declare: CSpriteBase Invader1; so I have declared the base for "invader1". In my initialisation for the game I do: sprbInvader1.init("data/invader1"); This loads the sprite frames from the directory given. So now the sprite base is setup. Now, I have CSprite. This is an actual sprite. As in it holds the x/y coordinates and has methods for moving the sprite around, drawing it to the screen etc. It has a protected member, a pointer to a CSpriteBase. Note: I also have a CEnemy class, which is derived from CSprite. This contains additional data related to specifically enemy sprites and enemy actions. It uses both the init and draw methods from CSprite so this cannot be the problem. So along with declaring my sprite base I also have: CEnemy test; And in my game initialisation I do: test.init(&sprbInvader1,40,40); This basically initialises the sprite so that it knows its an "invader1" sprite and it sets its x and y coords as 40. Then in my main game loop I call: test.draw(screen); Now this all works ok. It has the enemy object and it draws to the screen correctly at the right position. So now I move on. I create a vector: vector m_Enemies; So now I have an empty vector of enemies. I remove the code for the CEnemy object "test" from above and I now do: In the game initialisation: CEnemy temp; temp.init(&sprbInvader1,40,40); m_Enemies.push_back(temp); This in theory (as far as I understood) should create an enemy object, initialise it in the same way as the non-vector version, then "pushes"/"adds" it to the vector. So in theory I should have m_Enemies[0] as an enemy object right? Now when I add to the main loop: m_Enemies[0].draw(screen); The game runs but after a few milliseconds (when it comes to drawing) it closes, no errors, nothing. I''m pretty sure its a problem loading/initialising the frames for the sprite but I don''t know what I''m doing wrong. I also tried replacing the initialisation with: CEnemy temp; m_Enemies.push_back(temp); m_Enemies[0].init((&sprbInvader1,40,40); But this doesn''t work either. I really don''t know what I''m not doing right

Share this post


Link to post
Share on other sites
Try declaring the vector as

vector< CEnemy * > m_Enemies;

That is, if you haven't already. Seems the forum assumes the part after vector to be an HTML tag or something.

This means that you'll have to declare your temp CEnemy instances as pointers, then allocate memory with new. During shutdown, you'll have to iterate the vector and delete all the pointers.

"Skepticism.... that great rot of the intellect." - V.H.
Bah, what does HE know?


Albekerky Software


[edited by - sliderag on November 13, 2003 9:15:59 PM]

[edited by - sliderag on November 13, 2003 9:16:44 PM]

[edited by - sliderag on November 13, 2003 9:18:54 PM]

Share this post


Link to post
Share on other sites
Looking at your post again, I would definately say that the problem is because you are not using pointers for the vector. When your temp objects lose scope after the initialization function exits, the memory they are using is released to the system, leaving you with an empty reference in the vector. Using dynamically allocated pointers fixes this, because then that memory is only released when you want it to be, allowing you to use it in other functions than that in which it was allocated.

Share this post


Link to post
Share on other sites
Do you have access to a debugger? Try single stepping into the CEnemy.draw method and see what bad data is being used.

Make sure your copy constructor for CEnemy is working properly. One thing you should know is that vectors store copies of objects. So when you push_back(temp) you are actually storing a copy of temp not temp itself.

Share this post


Link to post
Share on other sites
Hmm yeah it was supposed to be

vector < CEnemy > m_Enemies

but was treated as a tag. Ok, so if I change it to a list of pointers, what else do I need to change?

I''m now doing:

m_Enemies.push_back(&temp);

and changed the . to the -> when accessing the draw method.
Still the same problem though.
What I was planning to do, is on game initialisation I do the following:

CEnemy temp;

for(int x=0; x < NUM_ENEMIES_PER_ROW; x++)
{
for(int y=0; y < NUM_ROWS; y++)
{
temp.init(&sprbInvader1, ___ , ___); // Where the ___ will contain a formula for assigning coords
m_Enemies.push_back(&temp);
}
}

So then I will have a grid of space invaders stored in the vector.

I will try debugging in a minute, but havn''t tried it before.

I used to use Delphi so I am familiar with that but havn''t needed or tried it yet.

Share this post


Link to post
Share on other sites
Ok well I''ve been debugging now.

The sprite base initialises alright. In the game initialisation, the CEnemey temp; object is created and initialised alright. And when I check the data for m_Enemies[0] its all there and what it should be.

Then in the game loop when I call:

m_Enemies[0].draw(screen), nothing seems to be initialised.

The method is as follows:


void CSprite::draw(SDL_Surface *destination)
{
m_LastUpdate = SDL_GetTicks();
if(m_Animating == 1)
{
if(m_LastUpdate + m_Base->getPause(m_Frame) < (int)SDL_GetTicks())
{
m_Frame++;
if(m_Frame > m_Base->getNumFrames()-1) m_Frame=0;
m_LastUpdate = SDL_GetTicks();
}
}


SDL_Rect dest;
dest.x = m_X;
dest.y = m_Y;

SDL_Surface *frame;
frame = m_Base->getImage(m_Frame);
SDL_BlitSurface(m_Base->getImage(m_Frame) , NULL, destination, &dest);
}


When i expand "this" I get all the integers (x,y,frame,animating) equal to -858993460.

So naturally when it comes to drawing it on the screen, it doesn''t have any frames to draw, and is trying to draw some really obscure frame number to some strange place.

But the data is all correct for m_Enemies[0] so why is it not correct in the .draw method?

Share this post


Link to post
Share on other sites
That is strange.

I might add some printf''s printing the address of the first element (&m_enemies[0]) occasionally. Perhaps the vector is getting relocated and hosing itself.

Another poster suggested using pointers. To tell the truth I have to agree. Using STL requires a lot of copying and copying pointers is much faster than copying objects.

Share this post


Link to post
Share on other sites
quote:
Original post by sliderag
Looking at your post again, I would definately say that the problem is because you are not using pointers for the vector. When your temp objects lose scope after the initialization function exits, the memory they are using is released to the system, leaving you with an empty reference in the vector. Using dynamically allocated pointers fixes this, because then that memory is only released when you want it to be, allowing you to use it in other functions than that in which it was allocated.

Please learn how std::vector works before spouting rubbish. The std::vector will store a dynamically allocated copy of temp.
quote:
Original post by Sabbac
Another poster suggested using pointers. To tell the truth I have to agree. Using STL requires a lot of copying and copying pointers is much faster than copying objects.


In what way does "using STL" require a lot of copying? Do you mean that a std::vector requires a lot of copying? If so, no, that depends entirely upon how it is being used. sanguineraven will have to read up and learn about the various different STL containers, and then decide which one best suits his needs.

Incidentally, I notice that you have a public member function init(). Note that you are not initialising with this member, you are assigning. If you want to initialise your class object, implement a constructor for the class.

As for your objects not being initialised properly, check your copy constructor and make sure that you are making deep copies, and check your other constructors/init() and make sure that these are initialising/assigning correctly.

[ Google || Start Here || ACCU || STL || Boost || MSDN || GotW || CUJ || MSVC++ Library Fixes || BarrysWorld || E-Mail Me ]

Share this post


Link to post
Share on other sites
quote:
Original post by sanguineraven
Yeah I'm using pointers at the moment. It's a vector of pointers to CEnemy. But for some reason when I use the draw method, its data is incorrect


Ah-Ha!

I bet it looks like this:

void fn()
{
CEnemy temp;
temp.init(...);
m_enemies.push_back(&temp);
}

void otherFn()
{
m_enemies[0]->draw(...);
}



If so the problem is that when temp goes out of scope the pointer to temp becomes invalid.
Try this instead:

void fn()
{
CEnemy* temp = new CEnemy;
temp->init(...);
m_enemies.push_back(temp);
}

void otherFn()
{
m_enemies[0]->draw(...);
}


hope that helps

[edit: speeling]

[edited by - sabbac on November 14, 2003 11:55:28 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Lektrix
In what way does "using STL" require a lot of copying?


What I mean by that is when you store something in a STL container you are truely storing a copy of the object. For any non-trivial class it costs more to copy an instance than copy a pointer.

Share this post


Link to post
Share on other sites
quote:
Original post by Sabbac
quote:
Original post by sanguineraven
Yeah I''m using pointers at the moment. It''s a vector of pointers to CEnemy. But for some reason when I use the draw method, its data is incorrect


Ah-Ha!

I bet it looks like this:

void fn()
{
CEnemy temp;
temp.init(...);
m_enemies.push_back(&temp);
}

void otherFn()
{
m_enemies[0]->draw(...);
}



If so the problem is that when temp goes out of scope the pointer to temp becomes invalid.
Try this instead:

void fn()
{
CEnemy* temp = new CEnemy;
temp->init(...);
m_enemies.push_back(temp);
}

void otherFn()
{
m_enemies[0]->draw(...);
}


hope that helps

[edit: speeling]

[edited by - sabbac on November 14, 2003 11:55:28 AM]


Yep!! That works, thankyou. I''ve been stuck on that for ages

Share this post


Link to post
Share on other sites