Weird behaviour encapsulated std::list in std::vector sometimes - c++

I am working on a RTS game. This game has buildings and actors. A building or actor is an instance of the buildings or actors class. These instances are stored in a std::vector for easy interaction by iterator id.
The actors and buildings can do tasks, these are stored in an std::list instantiated by the class in other words that list lives inside std::vector<actors>. The problem now is that every so often when information about this tasks needs retrieval or the tasks has to be removed from the list the program will crash with either "access violation", "trying to pop_front on empty list" or "trying to call front() on a empty list". Even though the previous line of code was a double check to see if the list was indeed not empty! It is also hard to reproduce because it happens every so often.
I suspect that someway somehow iterators or pointers get invalidated, since the list lives in a vector. I tried circumventing that by reserving space for 1600 units and 1600 buildings. However the problem still persists.
if (!this->listOfOrders.empty()) {
switch (this->listOfOrders.front().orderType) { //error here calling front() on empty list
case stackOrderTypes::stackActionMove:
this->updateGoal(this->listOfOrders.front().goal, 0);
break;
case stackOrderTypes::stackActionGather:
this->updateGoal(this->listOfOrders.front().goal, 0);
this->setGatheringRecource(true);
break;
}
}
I am really at a loss here.
Simplified class construct to illustrate:
enum class stackOrderTypes
{
stackActionMove,
stackActionGather
//and so on...
};
struct goal
{
int x;
int y;
}
struct orderStack
{
cords goal;
stackOrderTypes orderType;
};
class actors
{
public:
//other functions here
void doNextStackedCommand();
void stackOrder(cords Goal, stackOrderTypes orderType);
private:
//other stuff goes here
std::list<orderStack> listOfOrders;
};
std::vector<actors> listOfActors; //all actors live in here

To know what problem is causing this error, you need first to find exactly where in your code the problem is happening.
However, from what you describe I see a possible cause of you problem : items removals.
I suppose you have some loops iterating over your orders, and under some conditions you remove orders from your order list. Check if your code looks like this :
for (auto it = orderList.begin(); it != orderList.end(); ++it)
{
// Some code there
if (OrderIsFinished() == true)
orderList.erase(it);
// Some code there
}
This is a common mistake. After calling erase, the item pointed by the iterator it gets removed and it is invalidated. To keep iterators consistent after a removal, you need to change the way you iterate through all elements :
auto it = orderList.begin();
while (it != orderList.end())
{
// Some code there
if (OrderIsFinished() == true)
it = orderList.erase(it);
else
++it;
}

It was in fact a data race issue. There was a std::async updater running for builds while the update function was also called in the main thread!

Related

How to for loop with iterators if vector type is parent of two child types filling vector

I have this problem:
this is my loop for previously used child type
std::vector<Coin>::iterator coin;
for (coin = coinVec.begin(); coin != coinVec.end(); ++coin)
{
sf::FloatRect coinBounds = coin->getGlobalBounds();
if (viewBox.intersects(coinBounds))
{
if (playerBounds.intersects(coinBounds))
{
coin = coinVec.erase(coin);
break;
}
else coin->setTextureRect(currentFrame);
}
}
And the similar one for std::vector<Heal>.
I rebuild my code structure to: Coin is now child of Collectables.
There is now only one vector: std::vector<Collectables> which contains all collactable child classes objects like Coin, Heal etc.. Is there a way to make the code work with only one loop and iterators? If yes, how would you do that?
Thanks
I find out that my code is so universal, that I dont need to separate vector elements at all.
My solution here:
std::vector<Collectables>::iterator collect;
for (collect = collectVec.begin(); collect != collectVec.end(); ++collect)
{
sf::FloatRect collectBounds = collect->getGlobalBounds();
if (viewBox.intersects(collectBounds))
{
if (playerBounds.intersects(collectBounds))
{
collect = collectVec.erase(collect);
break;
}
else collect->setTextureRect(currentFrame);
}
}
And if you really need to separate elements, try this:
if (collect->getType() == ResourceManager::enums::textures::coin)
{
} else
if (collect->getType() == ResourceManager::enums::textures::health)
{
}
Where getType stores simply int id matching enum value.
Although seems that you have solved the problem, it is probably worth to tell how would you solve the initial problem.
As mentioned in the comments storing elements in the vector would result in object slicing, e.g.
std::vector<BaseClass> vect;
The elements of the vector would be able to store information about objects, which is common for classes, aka defined in BaseClass. If you want to be able to perform polymorphism(which you are trying to achieve in the example), you should store vector of pointers like this.
std::vector<BaseClass*> vect;
Each pointer would point to the address of the element, and thus object slicing won't happen.

C++, A way to update Pointers after vector resize, and erase vector objects without copying?

I believe this will be my first question for the site, so I apologize for any mistakes or errors in this post. I am a beginner C++ programmer as well, so forgive me if my questions come across as “noobish”.
Background: A collection of Parent Entity objects are created at startup (and currently not removed or added-to during runtime), and are then linked to a series of Activator Entity objects (both at the beginning, and during, runtime) through a Child Entity object. When establishing a link, the Parent generates a Child (which is stored in a local vector), and returns a pointer to the Child for the Activator to store.
Activators will “activate” children they are linked with, which will then do jobs based off internal and Parent settings. After being activated, they are also updated periodically by the Parent, continuing until eventually deactivating.
Below is a simplified example of the classes present.
class ParentEntity {
std::vector<ChildEntity> m_Children;
std::vector<ChildEntity*> m_ActiveChildren;
public:
//Funcs
ParentEntity(unsigned expectedChildren) { m_Children.reserve(expectedChildren); }
ChildEntity* AddChild(){
m_Children.push_back(ChildEntity(*this));
return &(m_Children.back());
}
void RemoveChild(unsigned iterator) {
//Can't figure a way to remove from the m_Children list without disrupting all pointers.
//m_Children.erase(m_Children.begin() + iterator); Uses Copy operators, which wont work as Const values will be present in Child
}
void AddActiveChild(ChildEntity* activeChild) {
m_ActiveChildren.push_back(activeChild);
}
bool Update(){ //Checks if Children are active,
if (!m_ActiveChildren.empty()) {
std::vector<ChildEntity*> TempActive;
TempActive.reserve(m_ActiveChildren.size());
for (unsigned i = 0; i < m_ActiveChildren.size(); i++) {
if (m_ActiveChildren[i]->Update()) {
TempActive.push_back(m_ActiveChildren[i]);
}
}
if (!TempActive.empty()) {
m_ActiveChildren = TempActive;
return true;
}
else {
m_ActiveChildren.clear();
return false;
}
}
else {
return false;
}
}
};
class ChildEntity {
public:
ChildEntity(ParentEntity& Origin) //Not const because it will call Origin functions that alter the parent
:
m_Origin(Origin)
{}
void SetActive() {
m_ChildActive = true;
m_Origin.AddActiveChild(this);
}
bool Update() { //Psuedo job which causes state switch
srand(unsigned(time(NULL)));
if ((rand() % 10 + 1) > 5) {
m_ChildActive = false;
}
return m_ChildActive;
}
private:
ParentEntity& m_Origin;
bool m_ChildActive = false;
};
class ActivatorEntity {
std::vector<ChildEntity*> ActivationTargets;
public:
ActivatorEntity(unsigned expectedTargets) { ActivationTargets.reserve(expectedTargets); }
void AddTarget(ParentEntity& Target) {
ActivationTargets.push_back(Target.AddChild());
}
void RemoveTarget(unsigned iterator) {
ActivationTargets.erase(ActivationTargets.begin() + iterator);
}
void Activate(){
for (unsigned i = 0; i < ActivationTargets.size(); i++) {
ActivationTargets[i]->SetActive();
}
}
};
With that all laid out, my three questions are:
Is there a way to update Pointers when a vector resizes?
When a Child is added, if it goes past the expected capacity, the vector creates a new array and moves the original objects to the new location. This breaks all of the Activator pointers, and any m_ActiveChild pointers, as they are pointing to the old location.
Is there a way to remove Child objects from the m_Children vector?
Since ChildEntity objects will host const items within them, copy assignment operations won’t work smoothly, and the Vector’s erase function won’t work. The m_Children vector could be rebuilt without the unwanted object through a temporary vector and copy constructor, but this leads to all of the pointers being wrong again.
Please let me know if there are any other suggested optimizations or corrections I should make!
Thank you all for your help!
Your problem, abstractly seen, is that on one hand you have collections of objects that you want to iterate through, kept in a container; and that on the other hand these objects are linked to each other. Re-ordering the container destroys the links.
Any problem can be solved by an additional indirection: Putting not the objects but object handles in the container would make re-ordering possible without affecting cross-references. The trivial case would be to simply use pointers; modern C++ would use smart pointers.
The disadvantage here is that you'll move to dynamic allocation which usually destroys locality right away (though potentially not if most allocations happen during initialization) and carries the usual run-time overhead. The latter may be prohibitive for simple, short-lived objects.
The advantage is that handling pointers enables you to make your objects polymorphic which is a good thing for "activators" and collections of "children" performing "updates": What you have here is the description of an interface which is typically implemented by various concrete classes. Putting objects in a container instead of pointers prevents such a design because all objects in a container must have the same concrete type.
If you need to store more information you can write your own handle class encapsulating a smart pointer; perhaps that's a good idea from the beginning because it is easily extensible without affecting all client code with only a moderate overhead (both in development and run time).

What data structure can I use to free memory within a contiguous stretch of memory?

I would like to simulate a population over time and keep a genealogy of the individuals that are still alive (I don't need to keep data about dead lineages). Generations are discrete and non-overlapping. For simplicity, let's assume that reproduction is asexual and each individual has exactly one parent. Here is a class Individual
class Individual
{
public:
size_t nbChildren;
const Individual* parent;
Individual(const Individual& parent);
};
In my Population class, I would have a vector for the current offsprings and of the current parents (the current parents being the offsprings of the previous generation).
class Population
{
private:
std::vector<Individual*> currentOffsprings;
std::vector<Individual*> currentParents;
public:
addIndividual(const Individual& parent) // Is called from some other module
{
Individual* offspring = new Individual(parent);
currentOffsprings.push_back(offspring);
}
void pruneDeadLineages() // At the end of each generation, get rid of ancestors that did not leave any offsprings today
{
// Collect the current parents that have not left any children in the current generation of offsprings
std::queue<Individual*> individualsWithoutChildren; // FIFO structure
for (auto& currentParent : currentParents)
{
if (currentParent->nbChildren() == 0)
{
individualsWithoutChildren.push(currentParent);
}
}
// loop through the FIFO to get rid of all individuals in the tree that don't have offspring in this generation
while (individualsWithoutChildren.size() != 0)
{
auto ind = individualsWithoutChildren.pop_front();
if (ind->nbChildren == 0)
{
ind->parent.nbChildren--;
if (ind->parent.nbChildren == 0)
{
individualsWithoutChildren.push(ind->parent);
}
delete ind;
}
}
}
void newGeneration() // Announce the beginning of a new generation from some other module
{
currentParents.swap(currentOffsprings); // Set offsprings as parents
currentOffsprings.resize(0); // Get rid of pointers to parents (now grand parents)
}
void doStuff() // Some time consuming function that will run each generation
{
for (auto ind : currentOffspings)
{
foo(ind);
}
}
};
Assuming that the slow part of my code will be looping through the individuals in the doStuff method, I would like to keep individual contiguous in memory and hence
std::vector<Individual*> currentOffsprings;
std::vector<Individual*> currentParents;
would become
std::vector<Individual> currentOffsprings;
std::vector<Individual> currentParents;
Now the problem is that I don't want to consume memory for ancestors that did not leave any offspring in the current generation. In other words, I don't want to keep whole vectors of length of the number of individuals per generation in the population for each generation. I thought I could implement a destructor of Individual that does nothing, so that the Individuals of the grand parent generation do not get killed at the line currentOffsprings.resize(0); in void Population::newGeneration(). Then in void Population::pruneDeadLineages(), I would explicitly delete the individuals with a method Individual::destructor() instead of using delete or Individual::~Individual().
Is it silly? Would it be memory safe (or yield to segmentation fault or memory leaks)? What other option do I have to 1) make sure that current generations individuals are contiguous in memory and 2) I can free the memory within this contiguous stretch of memory for ancestors that did not leave any offsprings?
I don't really understand why do you need to have your Individuals stored contiguously in memory.
Since you'll have to remove some of them and add others at each generation, you'll have to perform a reallocation for the whole bunch of Individuals in order to keep them contiguous in memory.
But anyway, I will not question what you want to do.
I think the easiest way is to let std::vector do the things for you. No need of pointers.
At each next generation, you move the offsprings from currentOffsprings to currentParents and you clear() the currentOffsprings.
Then, for each parent that do not have any children in the current generation, you can just use erase() from std::vector to remove them and consequently let the std::vector taking care of keeping its elements contiguous.
Better than 100 words, something like:
void Population::newGeneration()
{
currentParents.swap(currentOffsprings);
currentOffsprings.clear();
}
void Population::pruneDeadLineages()
{
currentParents.erase(std::remove_if(currentParents.begin(), currentParents.end(), [](const Individual & ind){return ind.nbChildren == 0;}), currentParents.end());
}
Of course it assumes that the parents and offsprings are defined in Population as:
std::vector<Individual> currentParents;
std::vector<Individual> currentOffsprings;
Note: As std::remove_if moves the elements to remove at the end of the container, the elements to keep stays contiguous and there is thus no reallocation when performing the erasing.
This way your two requirements (keep Individuals contiguous in memory and get rid of dead lineages) will be filled, without doing weird things with destructors,...
But as you have two std::vector, you are assured to have currentOffsprings stored contiguously in memory, same thing for currentParents.
But the two std::vectors are absolutely not guaranteed to be contiguous each other (But I think you are already aware of this and that it is not what you want).
Let me know if I have misunderstood your actual problem

Class destruction segfault

This post is not a duplicate. Read my question first.
I'm certainly missing something here. I would like to have my Entity class be able to destroy an instance of itself when the health quantity is zero.
virtual int takeDamage(int damage) {
health -= damage;
if(health <= 0) delete this;
}
What's wrong with the above code? The program crashes with a segfault when the last line above is called.
So far I have tried:
Making a custom destructor
Making a destructor function:
virtual void destroy(Entity*e) {
delete e;
}
Destroying the object where it was allocated
I removed the last line of takeDamage() and then called delete object from main.
if(tris[i]->getHealth() <=0) delete tris[i]; //called from the main function where a temporary collision detection occurs over all the entities in the program
I've located some of the issue, and it comes down to the following. The instances of all the Entity(s) in my program (of one particular specialization, ie: Triangles) are stored in a vector. For example, the above code uses this vector: vector<Triangle*> tris; (Triangle inherits Entity). Then, that vector is iterated through and various operations are performed, such as collision detection, AI, etc. Now, when one of the objects is deleted, the next time we have iterated through the entire vector, we come to the object which has been deleted. The next question is, what would I do to shrink that vector? (Now this is a good place to flag the question is perhaps needing of a separate question!)
Given your description, There is a way to do this safely using algorithm functions. The algorithm functions you may be looking for are std::stable_partition, for_each, and erase.
Assume you have the "game loop", and you're testing for collisions during the loop:
#include <algorithm>
#include <vector>
//...
std::vector<Entity*> allEntities;
//...
while (game_is_stlll_going())
{
auto it = allEntities.begin();
while (it != allEntitities.end())
{
int damage = 0;
// ... assume that damage has a value now.
//...
// call the takeDamage() function
it->takeDamage(damage);
++it;
}
// Now partition off the items that have no health
auto damaged = std::stable_partition(allEntities.begin(),
allEntities.end(), [](Entity* e) { return e->health > 0; });
// call "delete" on each item that has no health
std::for_each(damaged, allEntities.end(), [] (Entity *e) { delete e; });
// erase the non-health items from the vector.
allEntities.erase(damaged, allEntities.end());
// continue the game...
}
Basically what the loop does is that we go through all the entities and call takeDamage for each one. We don't delete any entities at this stage. When the loop is done, we check to see which items have no health by partitioning off the damaged items using the std::stable_partition algorithm function.
Why stable_partition and not just call std::remove or std::remove_if and before erasing the items, call delete on the removed items? The reason is that with remove / remove_if, you cannot do a multi-step deletion process (call delete and then erase it from the vector). The remove/remove_if algorithm functions assumes what has been moved to the end of the container (i.e. the "removed" items) are no longer needed and thus cannot be used for anything except for the final call to vector::erase. Calling delete on removed items is undefined behavior.
So to solve this issue, you need to "partition off" the bad items first, deallocate the memory for each item, and then remove them. We need to use a partitioning algorithm, so we have a choice of std::stable_partition or std::partition. Which one? We choose std::stable_partition. The reason why we chose std::stable_partition over std::partition is to keep the relative order of the items intact. The order of the items may be important for your game implementation.
Now we call stable_partition to partition the items into two sides of the entities vector -- the good items on the left of the partition, the bad items on the right of the partition. The lambda function is used to decide which entity goes where by testing the health value. The "partition" in this case is an iterator which is returned by stable_partition.
Given this, we call for_each, where the lambda calls delete on each item to the right of the partition, and then a vector::erase() to remove everything to the right of the partition. Then we loop again, redoing this whole process until the game is finished.
Another thing you will notice is the safety of the code above. If all entries have some health, then the calls to stable_partition, for_each, and erase are essentially no-ops. So there is no need to explicitly check for at least one item having no health (but nothing stops you to from doing so, if you feel you need this micro-optimization).
And also, make sure your Entity base class has a virtual destructor, otherwise your code will exhibit undefined behavior on the delete.
Edit: The takeDamage() function should be rewritten to not call delete this.
virtual int takeDamage(int damage) {
health -= damage;
return 0;
}

Iterating a changing container

I am iterating over a set of callback functions. Functions are called during iteration and may lead to drastic changes to the actual container of the functions set.
What I am doing now is:
make a copy of original set
iterate over copy, but for every element check whether it still exists in the original set
Checking for every element's existence is super-dynamic, but seems quite slow too.
Are there other propositions to tackle this case?
Edit : here is the actual code :
// => i = event id
template <class Param>
void dispatchEvent(int i, Param param) {
EventReceiverSet processingNow;
const EventReceiverSet& eventReceiverSet = eventReceiverSets[i];
std::copy(eventReceiverSet.begin(), eventReceiverSet.end(), std::inserter(processingNow, processingNow.begin()));
while (!processingNow.empty()) {
EventReceiverSet::iterator it = processingNow.begin();
IFunction<>* function = it->getIFunction(); /// get function before removing iterator
processingNow.erase(it);
// is EventReceiver still valid? (may have been removed from original set)
if (eventReceiverSet.find(ERWrapper(function)) == eventReceiverSet.end()) continue; // not found
function->call(param);
}
};
Two basic approaches come to mind:
use a task based approach (with the collection locked, push tasks onto a queue for each element, then release all parties to do work and wait till completion). You'll still need a check to see whether the element for the current task is still present/current in the collection when the task is actually starting.
this could leverage reader-writer locks for the checks, which is usually speedier than fullblown mutual exclusions (especially with more readers than writers)
use a concurrent data structure (I mean, one that is suitable for multithreaded access without explicit locking). The following libraries contain implementations of concurrent data structures:
Intel Thread Building Blocks
MS ConCrt concurrent_vector
libcds Concurrent Data Structures
(adding links shortly)
There is a way to do it in two steps: first, go through the original set, and make a set of action items. Then go through the set of action items, and apply them to the original set.
An action item is a base class with subclasses. Each subclass takes in a set, and performs a specific operation on it, for example:
struct set_action {
virtual void act(std::set<int> mySet) const;
};
class del_action : public set_action {
private:
int item;
public:
del_action(int _item) : item(_item) {}
virtual void act(std::set<int> mySet) const {
// delete item from set
}
};
class upd_action : public set_action {
private:
int from, to;
public:
upd_action(int _from, int _to) : from(_from), to(_to) {}
virtual void act(std::set<int> mySet) const {
// delete [from], insert [to]
}
};
Now you can create a collection of set_action*s in the first pass, and run them in the second pass.
The operations which mutate the set structure are insert() and erase().
While iterating, consider using the iterator returned by the mutating operations.
it = myset.erase( it );
http://www.cplusplus.com/reference/stl/set/erase/