I have a problem whereby a vector of pointers does not seem to be behaving in the polymorphic way I expected it to. Stranger is the fact that it works on every other object it points to.
shotgunNodes and rifleNodes both contain two integers which represent the appropriate location in a level to place the pickups I’m generating.
pickups is a vector of kpointers (parent class) and ShotgunPU and RiflePU are derived classes. I’ll post the headers and source below.
The strange problem is that if I break the code, one loop at a time, everything seems to be going fine. The first gun pointer is set to point at a rifle object. Fine. Then the next gun pointer is set to point at the next rifle object, at which point for some bizarre reason the previous pointer in the vector, that should point to the first rifle is cut down and now only points to the gun part of the rifle object, so I lose all of the derived functionality on it.
By the end of the loops, I have a vector of guns pointing to Gun Rifle Gun Shotgun where it should be Rifle Rifle Shotgun Shotgun.
int j = 0;
for (vec_i_sz i = 0; i < rifleNodes.size(); i++, j++)
{
riflePickups.push_back(RiflePU(agents, mesh));
riflePickups[i].Position(nodes[rifleNodes[i]].Position());
pickups.push_back(&riflePickups[i]);//point the pickup pointer to the rifle pickup
pickups[j]->Index(j);
pickups[j]->NodeIndex(rifleNodes[i]);
}
for (vec_i_sz i = 0; i < shotgunNodes.size(); i++, j++)
{
shotgunPickups.push_back(ShotgunPU(agents, mesh));
shotgunPickups[i].Position(nodes[shotgunNodes[i]].Position());
pickups.push_back(&shotgunPickups[i]);
pickups[j]->Index(j);
pickups[j]->NodeIndex(shotgunNodes[i]);
}
It’s probably also worth noting that this code (obviously the translated version, but in the same structure) works in the C# version of the program. So I doubt it’s the structure of the code. Is there something I don’t know about the way pointers work?
This is how the vectors are declared in the header where they are used:
std::vector<Pickup*> pickups;
std::vector<RiflePU> riflePickups;
std::vector<ShotgunPU> shotgunPickups;
I just noticed by writing this that they are not actually initialized in the initializer list before the loops run (in the constructor’s body), but shouldn’t this be OK because they are class types?
If they are being initialised in the list, it’s still happening.
pickups(std::vector<Pickup*>()),
riflePickups(std::vector<RiflePU>()),
shotgunPickups(std::vector<ShotgunPU>())
When you add items to a vector,
push_backcan invalidate all pointers into the container when it needs to resize its underlying buffer. Each time this happens, the pointers that you have already stored inpick_upsbecome garbage.1) You can
reservememory for all items inriflePickupsandshotgunPickupsupfront. This will ensure that those vectors won’t be resized while that many items are added, and addresses of items will remain the same.2) You can store the pointers in
pick_upsafter you have created all the items in both vectors, not while those vectors have not yet reached their final size.3) You can use
std::listover vector forriflePickupsandshotgunPickups. In a list, pointers to items are only invalidated if said item is erased.Eventually, do you really need any of this? Perhaps you could just store (preferably smart) pointers to dynamically allocated objects in just one vector.