C++ 在循环列表时,删除列表中的对象的正确方法是什么?
我有一个星型结构的列表。这些结构位于std::列表中 我正在双倍循环这个列表,并比较这些位置以检测碰撞。当发现碰撞时,我将删除质量最低的恒星。但是,当我在双循环中时,如何删除恒星,并保持循环继续检查更多碰撞 值得一提的是,第二个循环是反向循环 这里有一些代码C++ 在循环列表时,删除列表中的对象的正确方法是什么?,c++,list,std,erase,C++,List,Std,Erase,我有一个星型结构的列表。这些结构位于std::列表中 我正在双倍循环这个列表,并比较这些位置以检测碰撞。当发现碰撞时,我将删除质量最低的恒星。但是,当我在双循环中时,如何删除恒星,并保持循环继续检查更多碰撞 值得一提的是,第二个循环是反向循环 这里有一些代码 void UniverseManager::CheckCollisions() { std::list<Star>::iterator iStar1; std::list<Star>::reverse
void UniverseManager::CheckCollisions()
{
std::list<Star>::iterator iStar1;
std::list<Star>::reverse_iterator iStar2;
bool totalbreak = false;
for (iStar1 = mStars.begin(); iStar1 != mStars.end(); iStar1++)
{
for (iStar2 = mStars.rbegin(); iStar2 != mStars.rend(); iStar2++)
{
if (*iStar1 == *iStar2)
break;
Star &star1 = *iStar1;
Star &star2 = *iStar2;
if (CalculateDistance(star1.mLocation, star2.mLocation) < 10)
{
// collision
// get heaviest star
if (star1.mMass > star2.mMass)
{
star1.mMass += star2.mMass;
// I need to delete the star2 and keep looping;
}
else
{
star2.mMass += star1.mMass;
// I need to delete the star1 and keep looping;
}
}
}
}
}
void UniverseManager::CheckCollisions()
{
std::list::迭代器iStar1;
std::list::reverse_迭代器iStar2;
bool totalbreak=false;
对于(iStar1=mStars.begin();iStar1!=mStars.end();iStar1++)
{
对于(iStar2=mStars.rbegin();iStar2!=mStars.rend();iStar2++)
{
如果(*iStar1==*iStar2)
打破
Star&star1=*iStar1;
Star&star2=*iStar2;
if(计算距离(起始1.m位置,起始2.m位置)<10)
{
//碰撞
//得到最重的星星
如果(star1.mMass>star2.mMass)
{
star1.mMass+=star2.mMass;
//我需要删除star2并继续循环;
}
其他的
{
star2.mMass+=star1.mMass;
//我需要删除star1并继续循环;
}
}
}
}
}
您需要像这样利用擦除方法的返回值
iStar1 = mStars.erase(iStar1);
erase = true;
if (iStar1 == mStars.end())
break; //or handle the end condition
//continue to bottom of loop
if (!erase)
iStar1++; //you will need to move the incrementation of the iterator out of the loop declaration, because you need to make it not increment when an element is erased.
如果在删除某个项时不增加迭代器,并检查是否删除了最后一个元素,则应该没有问题。由于修改列表会使迭代器无效(因此不能增加迭代器),因此在更改列表之前,必须确保迭代器的安全 在大多数实现中,std::list是一个双链表,因此类似于
for(auto i=list.begin(), ii; i!=list.end(); i=ii)
{
ii = i; ++ii; //ii now is next-of-i
// do stuff with i
// call list.erasee(i).
// i is now invalid, but ii is already the "next of i"
}
最安全的方法是创建一个包含所有“碰撞”的列表,然后在“碰撞”上迭代调用list.remove(*iterator\u on\u collized)
(但效率低下,因为它具有O2复杂性)您希望使用erase()的结果来获取下一个迭代器并以不同的方式推进循环:
for (auto oit(s.begin()), end(s.end()); oit != end; )
{
auto iit(s.begin());
while (iit != end)
{
if (need_to_delete_outer)
{
oit = s.erase(oit);
break;
}
else if (need_to_delete_inner)
{
iit = s.erase(iit);
}
else
{
++iit;
}
}
if (iit == end)
{
++oit;
}
}
你所写的算法会认为每颗恒星都与自身发生了碰撞。考虑替换<代码> istAR2!=mStars.rend()with
iStar2!=iStar1
如果(*iStar1==*iStar2)中断,那么第一行就是这个;但是你的路更干净。所以我会改变它。但没有回答我的问题。啊,我现在明白了。考虑一下这个变化,因为否则你会比较每对恒星TWIC.istAR1= MSTAR。擦除(ISTAR1);还请注意,如果决定删除Star1,则不希望继续循环内部循环。您将比较更多的星星与刚才删除的星星。因此,如果我理解正确,调用erase将删除它当前指向的对象,然后返回列表中的下一个元素?您应该使哪个=迭代器?对于reverse::iterator,这是否也适用?如果我有reverse::iterator rit;我将rit=mStars.erase(rit);不是吗?它实际上并没有删除指针以释放指向的内存,它只是从列表中删除指针。您可以手动删除内存,也可以创建一个智能容器来执行此操作。正如您所指出的,对于反向迭代器,它的工作原理应该是相同的。