我有以下代码,但是当我运行它时,我间歇性地得到一个Debug Assertion Failed错误,原因是“vector iterator not dereferencable”。
我正在尝试使用该程序创建一堆2D形状(正方形和圆形),然后逐个移动它们,检查碰撞情况。当两个形状碰撞时,我希望它们被移除,直到(最多)剩下一个形状。大约三分之一的尝试导致成功的结果,程序发现四次碰撞,然后停止。其他时候,它会发现1-3次碰撞然后发生错误。
我还应该提一下,我对C ++比较陌生(是的,这是一个课程作业),所以如果我的代码中有任何其他新手错误,请指出它们!
我的移动和碰撞方法看起来很好,所以我没有将它们包含在这里。
Square * s1 = new Square(seedCoord(limit), seedCoord(limit), 2.0);
... //There is 9 new shapes created here (squares and circles)
std::vector<Shape*> shape;
shape.push_back(s1);
... //All 9 shapes added to the vector
int m = shape.size();
bool collision = false;
while(m>1) //Keep running until only one shape hasn't collided
{
for (auto i=shape.begin(); i!=(shape.end());) //Perform move on each shape in sequence
{
collision = false; //Set collision boolean to false
(*i)->move(seedCoord(0.5), direction[(rand() % 4)], limit); //Perform move on shape
for (auto j=shape.begin(); j!=(shape.end()-1);) //Check for collision with each shape in sequence
{
if((*i) != (*j)) //Ignore self when checking for collision
{
if((*i)->collide(*j)) //Check for collision
{
std::cout << "Collision between " << (*i) << " and " << (*j) << "\n";
m=m-2; //Lower shapes count by two (ie remove two collided shapes)
delete *i; //Delete pointer to initial shape
i = shape.erase(i); //Erase shape object
delete *j; //Delete pointer to collided shape
j = shape.erase(j); //Erase shape object
collision = true; //Set collision boolean to true
break; //Break out of internal for-loop (shape has been deleted so no more checks are necessary)
}
else
{
j++; //If no collision, move onto next shape
}
}
else
{
j++; //If i=j, move onto next shape
}
}
if(!collision) //If no collision with any shape, move onto next shape
{
i++; //If no collision with any shape, move onto next shape
}
else
{
break; //If collision has occurred, break out of external for-loop (shape has been deleted so no more checks are necessary)
}
}
}
答案 0 :(得分:2)
对擦除元素以及它们与容器末尾之间的元素的迭代器和引用无效。过去的迭代器也会失效。
我的猜测是,在您第二次致电erase(j)
时出现问题,j
是一个迭代器,指的是i
和shape.end()
之间的位置并且无效。
答案 1 :(得分:1)
您在同一向量上运行两个迭代器。擦除该向量的元素时,超过该元素的所有迭代器都将失效。这意味着在每次碰撞时,i
或j
都会失效,因为另一个碰撞会调用erase
。
擦除后继续使用迭代器。这给出了未定义的行为,意思是“任何事情都可能发生”。 “aything”意味着它可以在大多数时间工作,但有时它不会。考虑这种情况:
最后两个元素发生碰撞,i
为end()-2
,j
为end()-1
。首先你erase(i)
,意思是所有元素都被推到左边,包括指向的j
。 j
现在在概念上是无效的,但不仅仅是一个指针,它现在指向一个超过最后一个元素,即j == end()
。您现在继续调用delete *j;
,取消引用将触发断言的end()
迭代器。
答案 2 :(得分:0)
更仔细地查看代码,看起来您的问题是由于元素的擦除
即
i = shape.erase(i); //Erase shape object
...
j = shape.erase(j); //Erase shape object
现在你正确使用了vector.erase()中新返回的迭代器,但问题是i和j都是同一向量的迭代器。这意味着发生以下情况
i
向后移动一个位置之后有剩余的元素)不要删除循环中的元素,最好在循环体内将元素标记为“死”,然后在std::remove_if
的末尾使用while
环
shape.erase(std::remove_if(shape.begin(),
shape.end(),
isDead),
shape.end());
其中isDead
是functor定义的类似:
struct isDead
{
bool operator()(const Shape* pX) const
{
return pX->isDead();
}
};