std::vector question...

Started by
9 comments, last by TaskyZZ 18 years, 10 months ago
I have a class and have declared it as a vector: std::vector<clsBullets *> Bullets; The Bullet class takes care of the bullet through it's lifetime. So, my bullet class needs to be able to remove itself. When a bullet hits something I erase it like this: Bullets.erase(Bullets.begin()+iBulletNum); And this happens in the main portion of the program. Now, when the bullet class is updating itself (moving) and it comes to the end of it's life (maximum range), I need it to kill itself. How do I do that? How can I erase an element from the vector while inside the class that is inside the vector? Does this make sense? Thanks for any help!
Advertisement
Assuming you're enumerating over the bullets back out in your main program with something like this:

for(std::vector<clsBullets *>::iterator iter = Bullets.begin(); iter != Bullets.end(); iter++)    // Call move function, moves the bullet and checks for collisions    iter->move();


You can then make move() (or whatever equivalent method does the per-game tick handling) return a bool value: true if the object is to continue to exist, and false if it is dead (requesting to be removed from the list):

std::vector<clsBullets *>::iterator iter = Bullets.begin(); while(iter != Bullets.end())    // Call move function, moves the bullet and checks for collisions    if(!iter->move())        // Erase bullet        iter = Bullets.erase(iter);    else        iter++;


Hope this helps.
My first suggestion is to use std::list rather than std::vector as your container.


Next, give each bullet object an iterator to itself in the list of bullets. You may also have to give each bullet object a pointer to the actual list of bullets. There are variations on this depending on how you want to do it (for instance, you could search by this pointer, rather than storing iterators). Then have the bullet delete itself using its iterator.

Just be careful, you'll in effect be doing a "delete this;" statement, which is not a particularly safe thing to be doing. As you're not using smart pointers, you will actually have to use a "delete this;" statement right after you remove the bullet from the list by iterator within its own function.

More specificly, once you "delete this;" you must return from your function immediatly (don't have to, but its safest) and never reference any of the object's member data either (as it is invalid).


Another, different method would be to mark bullets as "dead", and remove them on the list's next iteration. (ie: remove them externally).

EDIT: The method matt suggests is a variation on this last method.
I am new to C++ and just learned about vectors a couple days ago. Don't know what std::list is, but I will look into it.

As for the solution, I am implementing what mattd suggested. My draw() function actually moves the bullets then draws them, so I just have it returning true if the bullet has died and then I remove the bullet in the next line of code in the main loop.

Thanks for the help guys.
I highly recomend you look into std::list. Being able to use all the containers where appropriate is a neccessary programmer skill.

A std::vector is like an array, a std::list is like a linked list. In most code, you should just be able to change "std::vector" to "std::list" and have it work.

Your code in particular, doing "Bullets.begin()+iBulletNum" is random access and won't work for a list. But you really shouldn't be doing that anyway in your situation.


Vector pros:
Faster.
Random access.

Cons:
Iterators become invalid if you change the vector
Very slow to add or remove anything except at the end (and even this can be slow)


List pros:
Insertion and removal are fast
Iterators remain valid when modifying the list

Cons:
Slower
Must access sequentially
i'm going ask is there a specific reason why your storing pointers to clsBullets and not the actual clsBullets themselfs, prefer the latter unless you have good reason not too.

Quote:Original post by Andrew Russell
Just be careful, you'll in effect be doing a "delete this;" statement, which is not a particularly safe thing to be doing. As you're not using smart pointers, you will actually have to use a "delete this;" statement right after you remove the bullet from the list by iterator within its own function.

More specificly, once you "delete this;" you must return from your function immediatly (don't have to, but its safest) and never reference any of the object's member data either (as it is invalid).


If your gonna go down that road you'll have to prevent static allocation otherwise your asking for trouble.
Quote:Original post by snk_kid
i'm going ask is there a specific reason why your storing pointers to clsBullets and not the actual clsBullets themselfs, prefer the latter unless you have good reason not too.



Mainly, just because I don't know what I am doing. :)

Quote:Original post by snk_kid
i'm going ask is there a specific reason why your storing pointers to clsBullets and not the actual clsBullets themselfs, prefer the latter unless you have good reason not too.



If I change this:

std::vector <clsBullets *> Bullets;

to this:

std::vector <clsBullets> Bullets;

then when I do this:

Bullets.push_back(new clsBullets(PosX+tmp.x,PosY+tmp.y,Facing,Heading));

I get an error. So, when it is no longer a pointer, how do I add a new one to the vector?

This is the error:

error C2664:
'std::vector<_Ty>::push_back' : cannot convert parameter 1 from 'clsBullets *' to 'const clsBullets &'
with
[
_Ty=clsBullets
]
Reason: cannot convert from 'clsBullets *' to 'const clsBullets'
No constructor could take the source type, or constructor overload resolution was ambiguous

What should my push_back look like?
Your push back will look like this;

Bullets.push_back(clsBullets(PosX+tmp.x,PosY+tmp.y,Facing,Heading));

When this line is called a tempory clsBullets object is created and then copied into the Bullets vector, the temport is then destoryed and the copy remains in the vector.
Quote:Original post by TaskyZZ
Quote:Original post by snk_kid
i'm going ask is there a specific reason why your storing pointers to clsBullets and not the actual clsBullets themselfs, prefer the latter unless you have good reason not too.



If I change this:

std::vector <clsBullets *> Bullets;

to this:

std::vector <clsBullets> Bullets;

then when I do this:

Bullets.push_back(new clsBullets(PosX+tmp.x,PosY+tmp.y,Facing,Heading));

I get an error. So, when it is no longer a pointer, how do I add a new one to the vector?

This is the error:

error C2664:
'std::vector<_Ty>::push_back' : cannot convert parameter 1 from 'clsBullets *' to 'const clsBullets &'
with
[
_Ty=clsBullets
]
Reason: cannot convert from 'clsBullets *' to 'const clsBullets'
No constructor could take the source type, or constructor overload resolution was ambiguous

What should my push_back look like?


I'm sorry if sounded offensive earlier, i wasn't trying to be. What i said is not valid in every case but in general its preferred where applicable of-course.

Anyways Example:

#include <vector>struct clsBullets {	  float x, y;  clsBullets(float x_, float y_): x(x_), y(y_) {}  //....};int main() {   std::vector<clsBullets> v;   v.push_back(clsBullets(3.0f, 4.3f));}


here is a very useful reference [wink], its worth spending some time on reading the "Concepts" of the standard library containers & algorithms.

This topic is closed to new replies.

Advertisement