I'm developing an Asteroid game clone but I'm facing a problem during erasing elements from vector of asteroids. So generally when I hit the asteroid it should split into 3 parts. So I create 3 new asteroids and erase the old one an then it crashes.
void Level::missleAsteroidCollision(){
std::cout<<this->asteroidVector.size()<<std::endl;
for(auto ptr = this->missleVector.begin();ptr!=this->missleVector.end();++ptr){
sf::FloatRect missleBounds = (*ptr)->shape.getGlobalBounds();
for(auto ptrTwo = this->asteroidVector.begin(); ptrTwo!= this->asteroidVector.end();++ptrTwo){
if(missleBounds.intersects((*ptrTwo)->shape.getBounds()) && (*ptrTwo)->isFinalForm == false){
for(int i = 0; i < 3; ++i){
this->createAsteroid((*ptrTwo)->origin,true);
}
delete *ptrTwo;
this->asteroidVector.erase(ptrTwo);
}
else if(missleBounds.intersects((*ptrTwo)->shape.getBounds()) && (*ptrTwo)->isFinalForm == true){
delete *ptrTwo;
this->asteroidVector.erase(ptrTwo);
}
}
}
}
First of all, when you use the .erease function, the iterator is changed so you need to update it, in your case, ptr = this->asteroidVector.erase(ptrTwo); the iterator will now point to the next element after deletion so keep that in mind (either you decrease the pointer by one or you only increase the ptr (ptr++) if you did not use the .erase function.
Secondly, I believe this->createAsteroid((*ptrTwo)->origin,true); creates new items, this will also invalidate the iterator, so one fix could be, creating the new asteroids after checking and deleting the old one. Maybe store the new asteroids in a vector created before the for loop, adding the new meteorites there and after the for loop add the vector to your current vector of asteroids.
Inserting an item into a vector (whether or not at the end of the vector) can invalidate all iterators to that vector. I suspect your createAsteroid does so.
Related
So here's my problem.. I have a 2d array of 2 char strings.
9D 5C 6S 9D KS 4S 9D
9S
If 3 found I need to delete the first 3 based on the first char.
card
My problem is I segfault almost anything i do...
pool is the 2d vector
selection = "9S";
while(col != GameBoard::pool.size() ){
while(GameBoard::pool[col][0].at(0) == selection.at(0) || cardsRem!=0){
if(GameBoard::pool[col].size() == 1){
GameBoard::pool.erase(GameBoard::pool.begin() + col);
cardsRem--;
}
else{
GameBoard::pool[col].pop_back();
cardsRem--;
}
}
if(GameBoard::pool[col][0].at(0) != selection.at(0)){
col++;
}
}
I've tried a series of for loops etc, and no luck! Any thoughts would save my sanity!
So I've tried to pull out a code segment to replicate it. But I can't...
If I run my whole program in a loop it will eventually throw a segfault. If I run that exact code in the same circumstance it doesn't... I'm trying to figure out what I'm missing. I'll get back in if I figure out exactly where my issue is..
So in the end the issue is not my code itself, i've got memory leaks or something somewhere that are adding up to eventually crash my program... That tends to be in the same method each time I guess.
The safer and most efficient way to erase some elements from a container is to apply the erase-remove idiom.
For instance, your snippet can be rewritten as the following (which is testable here):
using card_t = std::string;
std::vector<std::vector<card_t>> decks = {
{"9D", "5C", "6S", "9D", "KS", "4S", "9D"},
{"9S"}
};
card_t selection{"9S"};
// Predicate specifing which cards should be removed
auto has_same_rank = [rank = selection.at(0)] (card_t const& card) {
return card.at(0) == rank;
};
auto & deck = decks.at(0);
// 'std::remove_if' removes all the elements satisfying the predicate from the range
// by moving the elements that are not to be removed at the beginning of the range
// and returns a past-the-end iterator for the new end of the range.
// 'std::vector::erase' removes from the vector the elements from the iterator
// returned by 'std::remove_if' up to the end iterator. Note that it invalidates
// iterators and references at or after the point of the erase, including the
// end() iterator (it's the most common cause of errors in code like OP's).
deck.erase(std::remove_if(deck.begin(), deck.end(), has_same_rank),
deck.end());
So for anyone else in the future who comes across this...
The problem is I was deleting an element in the array in a loop, with the conditional stop was it's size. The size is set before hand, and while it was accounted for in the code it still left open the possibility for while(array.size() ) which would be locked in at 8 in the loop be treated as 6 in the code.
The solution was to save the location in the vector to delete and then delete them outside of the loop. I imagine there is a better, more technical answer to this, but it works as intended now!
for (double col = 0; col < size; ++col)
{
if(GameBoard::pool[col][0].at(0) == selection.at(0)){
while(GameBoard::pool[col][0].at(0) == selection.at(0) && cardsRem !=0){
if( GameBoard::pool[col].size() > 1 ){
GameBoard::pool[col].pop_back();
cardsRem--;
}
if(GameBoard::pool[col].size() <2){
toDel.insert ( toDel.begin() , col );
//GameBoard::pool.erase(GameBoard::pool.begin() + col);
cardsRem--;
size--;
}
}
}
}
for(int i = 0; i< toDel.size(); i++){
GameBoard::pool.erase(GameBoard::pool.begin() + toDel[i]);
}
I am in the process of creating a C++/SFML game engine. Every "entity" in the game has a pointer to it stored in a static vector in the Entity class, called entityRenderList. This vector is sorted by the Bubble Sort algorithm on each iteration of the game loop so that the sprites are drawn in the correct order.
Whenever an entity is deleted, it replaces its pointer in the vector with a NULL pointer. My algorithm should, by default, cause any NULL pointers it finds to be sorted to the back of the vector, where they are subsequently removed.
Here is the code for the sorting algorithm:
bool Entity::depthSortFunction(Entity* a, Entity* b)
{
if (b==NULL) return false; //any NULL values are moved to the back
if (a==NULL) return true;
else return (a->depth_) < (b->depth_);
}
void Entity::sortEntityRenderList()
{
if (entityRenderList.size()>1) {
//Any NULL values are brought to the top to be stripped off.
bool passMade=false;
Entity* temp;
int n=entityRenderList.size()-1;
for(int i=0; i<n; i++)
{
passMade=false;
for(int j=0; j<n-1; j++)
{
if(depthSortFunction(entityRenderList[j],entityRenderList[j+1]))
{
//then swap them
temp = entityRenderList[j+1];
entityRenderList[j+1] = entityRenderList[j];
entityRenderList[j] = temp;
//and then notify the entities of the change
if (entityRenderList[j]!=NULL) {entityRenderList[j]->renderListID=j;}
if (entityRenderList[j+1]!=NULL) {entityRenderList[j+1]->renderListID=j+1;}
passMade=true;
//std::cout<<"Swapping entries "<<j<<" and "<<j+1<<"...\n";
}
}
if (!passMade) {
break; //then it is sorted, as we have not needed to modify the array.
}
}
}
//Now, we strip off any NULL values from the top.
while (!entityRenderList.empty() && entityRenderList.back()==NULL) {
entityRenderList.pop_back(); //strip off last one
}
}
What should be happening is that any NULL pointers are removed from the vector on each run of the algorithm. However, this is not the case, and any NULL pointers stay right where they are, and appear to not be sorted at all.
NB: The passMade boolean is there so that if a pass of the array is made and no swaps were made, the algorithm stops.
Any help would be appreciated. Thanks in advance.
EDIT: The sorting algorithm code is slightly modified from here.
There is a bug in the j loop limit. For example, if the list has 10 elements, n is 9, n-1 is 8, and the largest value of j is 7. The loop can exchange elements 7 and 8 of a 10 element list. It cannot exchange the last pair, elements 8 and 9.
As suggested by a comment, it would be better and simpler to use a library sort that is already tested and working. Rather than adjust the renderListID fields as you go along, you could do them all in a single pass through the list at the end. If you do it after popping the NULL elements, you would not need to test for NULL in that loop.
for(int i=0; i<entityRenderList.size(); i++)
{
entityRenderList[i]->renderListID=i;
}
I am going crazy about two issues I am having with my code.
I am trying to delete an element from my vector containing a list of objects.
//Remove Object
if (button2 == true)
{
//go through objects and check collision
for (std::vector<cOBJECT*>::size_type i = 0; i != GameObjects.size(); i++)
{
//Check for collision and delete object
if (MouseRect(GameObjects[i]->getrect(), mx + offX, my + offY) == true)
{
//GameObjects[i]->~cOBJECT();
delete GameObjects[i];
GameObjects.erase(GameObjects.begin() + i);
}
}
} // if (button2 == true)
For some reasons I run into two issues.
1) Access violation reading location 0xFEEEFEEE.
It seems to somehow have an issues with me destroying the texture. If I take out the "delete ...." and replace it with the destructor of the object instead, it works fine.
2) Vector subscript out of range
So if I use the destuctor to pass the first problem. I run into the next one. Now even if I use "GameObjects.erase(GameObjects.begin());" I get the same error.
If you think carefully about what the operation you implemented does you will notice that when the i-th element matches you remove that element from the vector and the (i+1)-th element is moved to the i-th position, but at this point the end of the loop is reached and i is incremented, which means that you will not test the element that was in the (i+1) position originally (and is now in i-th position) and also that if the value of i is GameObjects.size() - 1 before the removal the variable i now has a value that is GameObjects.size()+1 and the loop won't terminate.
Regarding the issue with the delete, you should check you created the object. Unless it was allocated with new chances are that you should not call delete on the pointer.
I'm using cocos2d and box2d and I have up to 5 b2bodies that need to be destroyed at the same time. They are all added to a set std::set<b2Body*>row1RedArray; and added by row1RedArray.insert(spriteBody);, and i've deleted all the items in the array through iteration, but my program just crashes when I touch the screen after they are removed. Am I destroying the b2Bodies correctly?
//if that array is empty, then remove all objects from this array (row4)
if ((row4BlueArray.count == 0) && (row4.count >> 0) && (row4Removed == NO)) {
std::set<b2Body *>::iterator pos04;
for(pos04 = row4RedArray.begin(); pos04 != row4RedArray.end(); ++pos04) {
b2Body *rowBody = *pos04;
if (rowBody->GetUserData() != NULL)
{
for (CCSprite* sprite4 in row4) {
[self removeChild:sprite4 cleanup:YES];
}
//Adding the b2Body to the toDelete Set and then removing it from the set of b2Bodies
toDestroy.insert(rowBody);
row4RedArray.erase(rowBody);
row4Removed = YES;
}
}
}
std::set<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
b2Body *body = *pos2;
if (body->GetUserData() != NULL)
{
//Then removing the b2Body completely (this is all at the end of the tick method)
_world->DestroyBody(body);
}
}
Solution of Captain Obvlious in comments is obvious, but is not correct. Bodies should be destroyed by world->DestroyBody(). Its needed simple iterate through bodies, and destroy each by calling this method (and never call delete for b2Body, b2Fixture or b2Joint). There no way to destroy them all at once.
You should destroy the bodies via world->DestroyBody(), do not dispose of them in any other way. There is no way to remove them at the same time, but the removal of the body has to be done outside of the box2d world step. This means that if you iterate through your list and destroy the bodies you want next time the box2d world will be updated it will look like the bodies have been disposed of at the same time.
There are few issues on the C++ side which might cause undefined behaviour. One of them is removing from an container when iterating over it. Once you used erase on any container the iterators to that container become invalid. This is more less the code I would propose:
std::vector<b2Body *> toDestroy;
if ((row4BlueArray.count == 0) && (row4.count >> 0) && (row4Removed == NO))
{
for(std::set<b2Body *>::iterator pos04 = row4RedArray.begin(); pos04 != row4RedArray.end(); ++pos04)
{
b2Body *rowBody = *pos04;
if (rowBody->GetUserData() != NULL)
{
toDestroy.push_back(rowBody);
row4Removed = YES;
}
}
for (CCSprite* sprite4 in row4)
{
[self removeChild:sprite4 cleanup:YES];
}
}
for( std::set<b2Body *>::iterator pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2)
{
row4RedArray.erase( (*body) );
_world->DestroyBody( (*body) );
}
//I have put the toDestroy vector in as a local variable so this is not needed, but if you
//are having it as a member variable etc. you need to clear it before you are going to use
//it in next loop, otherwise it will try to delete the same elements a second time.
toDestroy.clear();
I'm not sure why you used a std::set for storing the b2Body pointers. Sets are generally slower then any unordered container, such us vectors. I have also removed the if (rowBody->GetUserData() != NULL) from the second for loop as you do that check when you add the objects to the toDestroy vector, it can be assumed that the objects passed the criteria for removal.
You also remove sprites from the scene when iterating over the row4 container ( I assume from the code it is a container of some sort ), but you never clear it. It might wise to do so after you deleted all of the elements in that container, which is happening here from what I can see. You also attempt to remove those sprites multiple times, with the "for (CCSprite* sprite4 in row4)" inside the for loop iterating the bodies, so if more then one body has passed the criteria to be removed you iterate through the row4 again to remove the sprites.
I'm not sure why you are removing the bodies based on "if (rowBody->GetUserData() != NULL) criteria", but that might be something that you require in your game, which isn't apparent from the provided code.
I was trying to erase pointer elements (the value in the map is a pointer) from the map and I saw the code here What happens to an STL iterator after erasing it in VS, UNIX/Linux?
for(map<T, S*>::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) {
// wilhelmtell in the comments is right: no need to check for NULL.
// delete of a NULL pointer is a no-op.
if(it->second != NULL) {
delete it->second;
it->second = NULL;
}
}
I am not sure if the 'delete it->second' with de-allocate the correct memory because the erase(it++) step already moves the iterator to the next object. By the time, it reaches the delete statement, it is pointing to the next element which we don't want to delete. Am I missing something?
I believe this will work as expected.
The third section of the for loop (where the iterator is erased and then incremented) executes after the first iteration, and so on for each relevant iteration. Thus, you're always erasing the element you've already "dealt with" in the loop contents.
A parallel example:
for (int i = 0; i < 1; ++i) { ...
You will still enter the loop and execute with i = 0 before incrementing i and checking the looping condition.
You may want to try another way:
while (T2pS.size() > 0) {
if (T2pS.begin()->second != NULL) {
delete T2pS.begin()->second;
}
T2pS.erase(T2pS.begin());
}