Help with an assertion error using vectors

Started by
6 comments, last by DaveBifti 15 years, 4 months ago
Hi, new to forums, reletively new to coding... I'm making a small game, involving monsters and my player, i have a vector of monsters that each have co-ordinates. My player moves around a virtual grid and when my player lands on a grid co-ordinate wich contains a monster i.e has the same co-ordinats, the monster is deleted from the vector. Now thus far, the assertion error seems to be random, here's my source where i think the assertion error is caused


for(int k = 0; k <= gameSettings.numMonsters; k++){
					if(myPlayer.getPosRow() == monsterVector[k].getPosRow() && myPlayer.getPosColumn() == monsterVector[k].getPosColumn()){
						monsterVector.erase(monsterIter+k);
						gameGrid[myPlayer.getPosRow()][myPlayer.getPosColumn()] = CLEAR;
						gameSettings.numMonsters--;
						cout << "Found monster and killed it!\n";
						for(int i = 0; i <= gameSettings.numMonsters; i++){
							cout << "Monster " << i+1 << " position: ";
							monsterVector.displayPos();
						}
					}
				}


The error: Debug Assertion failed Expression("this->_Has_Container()",0) for information etc etc...... abort retry ignore... any ideas? as i said it's fairly random but has a tendency to happen when the number of monsters reaches 2 or 3. When i break, the compiler takes my to the vector template at this function

_Myt& operator+=(difference_type _Off)
		{	// increment by integer
                _SCL_SECURE_VALIDATE(this->_Has_container());  /*Points to this line*/
		_SCL_SECURE_VALIDATE_RANGE(
			_Myptr + _Off <= ((_Myvec *)(this->_Getmycont()))->_Mylast &&
			_Myptr + _Off >= ((_Myvec *)(this->_Getmycont()))->_Myfirst);
		_Myptr += _Off;
		return (*this);
		}

Advertisement
Quote:
for(int i = 0; i <= gameSettings.numMonsters; i++){
cout << "Monster " << i+1 << " position: ";
monsterVector.displayPos();
}

This looks suspicious to me. If numMonsters is greater than monsterVector.size(), you'll have problems. Why do you need to track the number of monsters when you can just look at the size of your monster vector? Storing this value separately seems to me like it only adds more things to go wrong.

Also,
Quote:
monsterVector.erase(monsterIter+k);


What is monsterIter? You're not holding on to an iterator into your vector somewhere, are you? Iterators easily become invalidated (say, by calling erase() on the container), so you shouldn't be storing them. And if you have an iterator into your container, why aren't you using that to loop over all the vector elements?

A few other things, now that I think about it:
-Your loop will skip over some monsters as it is currently written. Consider, you have 4 monsters, the second gets removed:
When k = 1, remove monster at index 1.
This will shift everything else in the array down, so the monster at index 2 is now at index 1, etc.
Increment k. k = 2 now, so the monster at index 1 (which was at index 2 prior to this loop iteration) will get skipped over.

-Why do you print the location of every monster every time one gets erased?
i was getting errors with the .size() member function i can't remember the exact content, may have been the same assertion error... tracking in this way should give me the exact size of the vector though?

ok i'll take it out, its only used to print the monster positions so i could test, rather than spend ages looking for the monsters, ill test some more now.

[edit] monsterIter is my vector iterator...

vector<Monster>::iterator monsterIter = monsterVector.begin();

can you elaborate on using the iterator to loop through my elements?
this happens when you try to randomly access([]) past the size of the vector,if you can't know the exact number of monsters before starting to fill the vector, you have to use push_back(), or check against Vector.size() before you access that position in the vector, ie.

for(int i = 0; i < SomeNumber;i++)
{
if(i < List.size())
List = whatever;
}
if you know the number of monsters, then resize() the vector before you fill it, this option performs better because it cuts down on the amount of dynamic memory allocation involved.


--------------------------------------Not All Martyrs See Divinity, But At Least You Tried
ok all the monsters positions are printed after 1 is erased to give help to me for testing, as oppsosed to aimlessly navigating around my grid trying to find the monsters and kill them as all the monsters(10 in total) are randomly positioned at start.

[edit]

so if i store the index position in a variable while the for loop is iterating, then when the loop exits, use erase() with the iterator and index variable instead.
Managed to fix it, you put me on the right track. i've split the code up a little, it may have been something to do with how i was erasing the first and last elements, i'm not too sure but what i have here rectified the problem although its a little messy at the moment...

for(int k = 0; k < monsterVector.size(); k++){	if(myPlayer.getPosRow() == monsterVector[k].getPosRow() && myPlayer.getPosColumn() == monsterVector[k].getPosColumn()){		indexPos = k;		eraseMonster = true;	}}


if(eraseMonster == true){	if(indexPos == monsterVector.size()){		monsterVector.pop_back();	}	else if(indexPos == 0){		monsterVector.erase(monsterVector.begin());	}	else{		monsterVector.erase(monsterIter+indexPos);	}	gameGrid[myPlayer.getPosRow()][myPlayer.getPosColumn()] = CLEAR;	gameSettings.numMonsters--;	cout << "Found monster and killed it!\n";		for(int i = 0; i < monsterVector.size(); i++){	cout << "Monster " << i+1 << " position: ";		monsterVector.displayPos();	}	eraseMonster = false;}
The STL already provides perfectly fine algorithms for removing elements that satisfy a predicate from a range. Untested code:

#include <algorithm>bool collides(const Monster& m){    return myPlayer.getPosRow   () == m.getPosRow   ()        && myPlayer.getPosColumn() == m.getPosColumn();}// somewhere in your code where you want to delete collided monstersmonsterVector.erase(std::remove_if(monsterVector.begin(), monsterVector.end(), collides),                    monsterVector.end());


[Edited by - DevFred on December 2, 2008 1:16:45 PM]
i've tested and is working fine, i thought it wasn't as i hadn't printed any statement verifying a hit or checking the monsterVector in debug at first lol.

very handy indeed, thank you!!

This topic is closed to new replies.

Advertisement