Implementing objects with short life time but that have to be created frequently
#1 Members - Reputation: 615
Posted 06 November 2012 - 08:14 PM
Everytime a player shoots a bullet, bullet object is created with new operator. But I figured this leads to calling new and delete as much as 50 times per second(Guessing this is going to be a performance issue) since there are multiple players shooting at each other simultaneously.
So I considered using a "recycle bin" for bullet object. I would preallocate about 200 bullet objects and if a bullet is destroyed, I can mark the bullet dead and revive it later when needed. But then I have to search for available bullet and that searching can take time...
How should I implement this?
#2 Members - Reputation: 571
Posted 06 November 2012 - 08:21 PM
#3 Members - Reputation: 615
Posted 06 November 2012 - 08:43 PM
I don't quite understand what you are saying. Can you be more clear?You can save a lot of time once you realize that the order of the bullets in memory doesn't matter. When bullet is deleted, memcpy the last bullet in the list to the deleted bullet's place, that way all the active bullets will be first and you can bust add a new one to the end
#4 Moderators - Reputation: 3968
Posted 06 November 2012 - 08:52 PM
When a bullet needs to be deleted you copy the last 'alive' bullet down to it's location and then reduce the number of bullets which are 'alive' in the world (unless, of course, the bullet count is '1', at which point you just reduce the count to zero).
So if you have 49 bullets 'alive' and the 3rd bullet 'dies' you would do something like bullets[3] = bullets[48]; --bulletCount;
#5 Marketplace Seller - Reputation: 8952
Posted 06 November 2012 - 08:56 PM
//Find the dead bullet's location.
iterator locOfDeadBullet = ...;
//Move the dead bullet to the end of the vector.
std::swap(myVector.back(), *locOfDeadBullet);
//Remove the last element in the vector (i.e. the dead bullet).
myVector.pop_back();
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal
#7 Marketplace Seller - Reputation: 8952
Posted 06 November 2012 - 09:59 PM
Why? Vector is optimized for iterating over the elements. List is optimized for inserting elements into the middle of the container.
Which will you be doing more? (Hint: You'll iterate over the entire list at least once a frame to draw the bullets. You'll probably only add a bullet only once every several frames)
Both, if used properly, can speedily add new elements to the end (vector does it speedily if the capacity is large enough, list always does it speedily). List is better for re-ordering, inserting, or removing. Vector, using the swap-to-end technique mentioned by everyone above, can pop and add easily enough when you don't require your elements to be in a specific order - which in this case you don't require.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal
#8 Members - Reputation: 615
Posted 07 November 2012 - 06:42 AM
Ok vector is better in that aspect, but I was asking if I pop an element out from a list, does list free its memory unlike vector? A vector doesn't shrink even if I pop an element out, so it doesn't have to re allocate the memory.You could use a list, however, vector is better in this situation.
Why? Vector is optimized for iterating over the elements. List is optimized for inserting elements into the middle of the container.
Which will you be doing more? (Hint: You'll iterate over the entire list at least once a frame to draw the bullets. You'll probably only add a bullet only once every several frames)
Both, if used properly, can speedily add new elements to the end (vector does it speedily if the capacity is large enough, list always does it speedily). List is better for re-ordering, inserting, or removing. Vector, using the swap-to-end technique mentioned by everyone above, can pop and add easily enough when you don't require your elements to be in a specific order - which in this case you don't require.
So for a list, to add a bullet, it first uses new to allocate a space, and then constructs the bullet object.
But for a vector, it constructs the bullet object right away because memory is already allocated.
Am I right?
Edited by lride, 07 November 2012 - 06:53 AM.
#9 Members - Reputation: 1408
Posted 07 November 2012 - 07:43 AM
You should stay with the "simple solution" that is working, and then replace it when you have performance problems and found that this is a significant resource problem.
That said, the question can still be interesting to discuss, from a design point of view. One thing that is good to do, however, is to code the algorithms in such a way as to improve the possibility to change them later on. To code for flexibility.
#10 Members - Reputation: 2772
Posted 07 November 2012 - 08:54 AM
The standard C++ containers use a pooled-allocation strategy. The don't use new and delete for memory allocation, they use a std::allocator object (which may or may not use new and delete) which will actually keep the memory hanging around after a contained object is freed. This allows better amortized performance as objects are added and removed from a list (or vectors are created and destroyed) at the expense of monotonically increasing memory usage over time. If you need to know which approach is best you need to measure.So for a list, to add a bullet, it first uses new to allocate a space, and then constructs the bullet object.
But for a vector, it constructs the bullet object right away because memory is already allocated.
If you don't have actual numbers from your performance analysis, you're not doing optimization so much as ritualized superstition.
Professional Free Software Developer
#11 Members - Reputation: 370
Posted 07 November 2012 - 09:28 AM
You allocate the array
Bullets **bullets= new Bullets*[200]
Then you make 2 lists:
list<Bullets*> dead_bullets, alive_bullets
....first all bullets(pointers) are in the dead_bullets and when a bullet is needed you put it into the alive_bullets and remove it from dead_bullets.
edit:
of course you fill the array first:)
for(...)
bullets[i]= new Bullet()
Edited by Aliii, 07 November 2012 - 09:31 AM.
#12 Marketplace Seller - Reputation: 8952
Posted 07 November 2012 - 10:27 AM
Basically, yes. However, if vector runs out of free allocated memory, it'll have to get a new chunk of memory, and move every element to the new chunk of memory.So for a list, to add a bullet, it first uses new to allocate a space, and then constructs the bullet object.
But for a vector, it constructs the bullet object right away because memory is already allocated.
Am I right?
Vector holds all its elements in one continuous block of memory (faster traversals, slower insertion), list holds each element in their own block of memory (longer traversals, faster insertion).
If you know in advance how many elements you'll have the vector hold, you can call vector.reserve() and then push_back() and pop_back() without fear of reallocation causing an unexpected slowdown. By "slower" and "faster" we're talking about time periods that all less than 1/100,000th of a second - unless you are really hitting everything tens of thousands of times a frame, these kinds of "which is faster in what situation" issues can mostly be ignored until you find yourself actually needing the extra speed.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal
#13 Members - Reputation: 314
Posted 07 November 2012 - 11:42 AM
I would guess for bullets it's not that optimal, but for other objects that have a predictable life time it's a simple way to prevent memory leaks.
#14 Moderators - Reputation: 6658
Posted 07 November 2012 - 02:23 PM
Not necessarily. The standard allows pooled allocation, but doesn't require it.The standard C++ containers use a pooled-allocation strategy.
Actually std::allocator itself is required to use new to allocate memory, though how often it is used (e.g. if it is called with every call to allocate()) is left unspecified. Other allocators may or may not use new.The don't use new and delete for memory allocation, they use a std::allocator object (which may or may not use new and delete) which will actually keep the memory hanging around after a contained object is freed.






