2016-12-01 85 views
1

我寫了這個簡單的測試程序。但我不明白這裏會發生什麼。因爲在輸出一件奇怪的事情:列表元素被刪除時,迭代器結束時會發生什麼?

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)?

+1

if中的== 0是多餘的,實際上整個if是無用的,因爲'it!= end()'會處理這個問題。我不確定你爲什麼說第一個元素有兩次?它看起來像你要刪除位置1和3的元素,因此打印元素0和2. – Borgleader

+0

感謝您的答案。是的,它打印元素0和2,但它在第一個元素上加兩次0.1。我不明白爲什麼:它應該是 (0.31,0.91)和(0.31,0.71) – Susliks

+0

就像旁邊一樣,這樣做的典型模式是* erase-remove idiom * with l.erase(std: :remove_if(...),l.end())'。 – ArchbishopOfBanterbury

回答

7
it=list.erase(it); 

這會刪除元素it。然後在之後返回迭代器位置

當您的for循環完成迭代時,它會前進it,通過++然後檢查它是否等於end()

所以你的循環都會在每次擦除後跳過元素。不好。如果它擦除最後一個元素,它就會通知最後一個迭代器,這是非法的。

for循環標題中刪除++it。在循環的底部,提前itit處擦除,而不是兩者都不是。

奇怪的打印行爲是由於UB造成的。您在位置0處遞增數據。您在位置1處遞增數據,然後將其刪除。您跳過位置2.您在位置3增加數據,然後刪除它。您超前結束迭代器(未定義的行爲)。然後發生隨機事件,恰好會再次增加數據位置0和2。作爲一個猜測,末端迭代器上的++恰好會循環回到特定情況下的第一個元素(這根本不能保證,但是UB會發生任何事情)。然後第二個循環正常運行,在兩個元素處遞增數據並刪除任何內容。

相關問題