google is your friend, but…
the basic idea behind an “object pool” is to determine the MAXIMUM number of active objects at any single time, then precreate a list of that number of objects. you never actually destroy them, you simply set them active/inactive. implementation details will vary as to exactly “what” you’ll want to do when activating/deactivating (fe physics involved? might need to also set isSensor=true/false and change x/y to onscreen/way-out-in-the-middle-of-nowhere, etc), but essentially:
to fire a bullet: pick one of the inactive objects and activate it
update bullets: process all of those that are “active”
to kill a bullet: deactivate it, making it available again to activate
the other number you MIGHT want is the TYPICAL number of active objects at any single time, as this may affect your strategy and data structures for managing the inactive/available list versus the active/inuse list. for example, if your MAXIMUM is 20 and your TYPICAL is near that, say >15, then you can probably just “set a flag” on your objects and iterate the entire list of 20 whenever processing it.
in that case, the “overhead” of list management of some fancier data structure probably isn’t worth it.
on the other hand, say you have a “super weapon” that very occassionally fires 100 bullets (so max=100, typ=15) then it would be inefficient to process all 100 every time looking for JUST the 15 typically active ones. in such a case you might WANT to do that extra bit of “list management” to maintain separate active/inactive lists to reduce needless iteration. essentially you’re just moving objects between the two lists to indicate their current status.
fwiw, if your use is REALLY mixed/dynamic, then one of the better (imo) solutions is THREE lists: a simple “array” for the entire pool (which remains static), then two separate linked lists pointing INTO that array for your maintained active/inactive lists - this makes all operations (find, iterate, remove/add) efficient.
hth