vector subscript out of range

Hi there,

I’ve been playing around with classes today and just found out how to use vectors (at least I got it to work somehow). But now I get an error when I delete some objects in those vectors when they touch each other.

This is the loop that checks if they touch and then deletes them if so:

  
for( int i = 0; i < baelle.size(); i++)  
	{  
		for(int j = 0; j < baelle.size(); j++)  
		{  
			float dist = ofDist(baelle[j].x, baelle[j].y, baelle[i].x, baelle[i].y);  
			if(dist < baelle[j].radius && dist > 0)  
			{  
				baelle[i].radius += baelle[j].radius;  
				baelle.erase( baelle.begin() + j );  
			}  
		}  
			  
		baelle[i].draw();  
  
		if(ofDist(baelle[i].x, baelle[i].y, ofGetMouseX(), ofGetMouseY()) < 180)  
		{  
			baelle[i].moveTo();  
			cout << baelle.size() << endl;  
		}  
	}  
	baelle.shrink_to_fit();  

unfortunately I sometimes get an error saying: “Expression: vector subscript out of range”
I also attached the files for better understanding

I hope someone can and is willing to help :slight_smile:
Thanks in advance!

ball.cpp

ball.h

main.cpp

testApp.cpp

testApp.h

The problem is because your looping over the vector twice (i and j) and potentially deleting an item in the second loop causing the first loop to go out of range. If baelle.size(); in the first loop i is 10 and then you delete in the second loop baelle.size(); is now 9 but the first loop is set to iterate over 10 items…one that now doesn’t exist.

You could add a bool var to your ball class,

  
 bool alive = true;   

for example. and set this to false instead of deleting the item from the vector. Then you could do a clean up routine at the end. You maybe better using the alive flag to decide whether you using the data to do calculations / draw rather than deleting the item from the vector as vectors are fast storage containers when items arent being added and removed alot. If you want to do alot of additions and deletions then Lists are much faster

http://www.cplusplus.com/reference/list/list/

  
  
for( int i = 0; i < baelle.size(); i++)    
    {    
        for(int j = 0; j < baelle.size(); j++)    
        {    
            float dist = ofDist(baelle[j].x, baelle[j].y, baelle[i].x, baelle[i].y);    
            if(baelle[i].alive && dist < baelle[j].radius && dist > 0)    
            {    
                baelle[i].radius += baelle[j].radius;    
                //baelle.erase( baelle.begin() + j );    
                 baelle[i].alive = false;  
            }    
        }    
                
        baelle[i].draw();    
    
        if(ofDist(baelle[i].x, baelle[i].y, ofGetMouseX(), ofGetMouseY()) < 180)    
        {    
            baelle[i].moveTo();    
            cout << baelle.size() << endl;    
        }    
    }    
// do the clean up and dleete the items.  
for( int i = 0; i < baelle.size(); i++)    
    {  
 if(!baelle[i].alive) baelle.erase( baelle.begin() + i );    
}  
    baelle.shrink_to_fit();  
  

Great points from maximillion

I’ll just mention that ofRemove() can be really helpful. here’s a small gist with an example of using it:

https://gist.github.com/roxlu/1084487

it’s a wrapper around remove if code, ie std::erase(std::remove()) http://en.wikipedia.org/wiki/Erase-remove-idiom

thanks for your help.
I thought that the resizing (baelle.shrink_to_fit():wink: might help me with the second loop recognize, when an entry is deleted (I tried to put it right in front of the second loop, but that didnt help)
I’ll try it with a list again, thanks :slight_smile:

edit:

ok with the second loop cleaning up the vector it worked fine. Thank you maximillion!

but now I have problems with converting everything to a list (because lists are new to me as well)

in my testapp.h I declarate:

  
Ball theBall;  
		std::list<Ball> baelle;  
		std::list<Ball>::iterator it;  

and in testapp.ccp in setup I try to insert actual balls in the list:

  
for(int i = 0; i < 300; i++)  
	{  
		baelle.insert(it, Ball());  
		++it;  
	}  

but here I get an error saying: "Expression: list emplace iterator outside range"
even if I dont write ++it.


I’m also not sure how to loop through the list (once it works). I’d try it with an iterator. Can you tell me whether this would be correct:

  
  
	for(auto l = baelle.begin(); l != baelle.end(); ++ l)  
	{  
	}  

or is this better (i read both solutions online but I’m not sure whether one is better than another and why)

  
  
list<Ball>::iterator iter;  
	for(iter = baelle.begin(); iter != baelle.end(); iter++)  
	{  
iter -> doSomething();  
	}  

thanks in advance :slight_smile: