列表元素被删除时,迭代器结束时会发生什么?
问题描述:
我写了这个简单的测试程序。但我不明白这里会发生什么。因为在输出一件奇怪的事情:列表元素被删除时,迭代器结束时会发生什么?
std::list<std::pair<double,double>> l;
l.push_back({0.3,0.9});
l.push_back({-0.3,0.5});
l.push_back({0.3,0.7});
l.push_back({1.2,1.83});
for(auto it=l.begin(); it!=l.end(); ++it){
double lx= it->first + 0.01;
double ly= it->second + 0.01;
it->first = lx;
it->second = ly;
if(lx < 0.0 || lx > 1.0 || ly < 0.0 || ly > 1.0){
it = l.erase(it);
}
如果我打印的清单,我得到:
0.32, 0.92
0.31, 0.71
为什么迭代器返回的第一个元素(两次+ 0.1)?
答
it=list.erase(it);
这会删除元素it
。然后在之后返回迭代器位置。
当您的for
循环完成迭代时,它会前进it
,通过++
然后检查它是否等于end()
。
所以你的循环都会在每次擦除后跳过元素。不好。如果它擦除最后一个元素,它就会通知最后一个迭代器,这是非法的。
从for
循环标题中删除++it
。在循环的底部,提前it
或在it
处擦除,而不是两者都不是。
奇怪的打印行为是由于UB造成的。您在位置0处递增数据。您在位置1处递增数据,然后将其删除。您跳过位置2.您在位置3增加数据,然后删除它。您超前结束迭代器(未定义的行为)。然后发生随机事件,恰好会再次增加数据位置0和2。作为一个猜测,末端迭代器上的++
恰好会循环回到特定情况下的第一个元素(这根本不能保证,但是UB会发生任何事情)。然后第二个循环正常运行,在两个元素处递增数据并删除任何内容。
if中的== 0是多余的,实际上整个if是无用的,因为'it!= end()'会处理这个问题。我不确定你为什么说第一个元素有两次?它看起来像你要删除位置1和3的元素,因此打印元素0和2. – Borgleader
感谢您的答案。是的,它打印元素0和2,但它在第一个元素上加两次0.1。我不明白为什么:它应该是 (0.31,0.91)和(0.31,0.71) – Susliks
就像旁边一样,这样做的典型模式是* erase-remove idiom * with l.erase(std: :remove_if(...),l.end())'。 – ArchbishopOfBanterbury