2016-06-11 61 views
2

我遇到了一些奇怪的行爲,使用了std :: list。問題是,當我刪除列表中的當前元素時,它會使該元素無效。當我瀏覽具有for(auto& iter : list)循環的元素時,它會卡在應該刪除的元素上。我有一個最小的可編譯的例子來說明這一點:在std :: list中刪除不需要的結果(C++)

#include <iostream> 
    #include <list> 
    #include <memory> 
    int main() { 
     std::list<unsigned int> wholeNumbers; 
     while(wholeNumbers.size() < 20) { 
      wholeNumbers.push_back(wholeNumbers.size()); 
     } 
     for(auto wholeNumber : wholeNumbers) { 
      std::cout << "Deleting entries. Value is: " << wholeNumber << std::endl; 
      std::cout << "Old size: " << wholeNumbers.size() << std::endl; 
      wholeNumbers.remove(wholeNumber); 
      std::cout << "New size: " << wholeNumbers.size() << std::endl; 
     } 
    } 

的這個期望的結果是,以噴出出遞增值和遞減的尺寸。但是,我正在經歷的結果如下:

Deleting entries. Value is: 0 
Old size: 20 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 1901208 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 1901208 
Old size: 19 
New size: 19 

然後,這會重複無限期。

我的編譯器的信息是:gcc version 5.3.0 (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project)

我很好奇,如果我是相信這應該工作,我打算錯了。

最好的問候,

+0

你正在使你的迭代器失效。 – erip

+3

啊。看到你的評論,它終於被提了出來。當我刪除它時,它變成無效,並且不能移動到下一個,因爲指針不再在元素中退出。因此,刪除元素應該在'remove_if'語句中完成,而不是在'for'循環中。謝謝。 –

+0

Spot on。好的結論! – erip

回答

2

http://en.cppreference.com/w/cpp/container/list/erase

引用和迭代器擦除元件失效。

基於循環的範圍使用隱式迭代器。 remove正在擦除迭代器指向的元素,因此它變得無效並且您有未定義的行爲,並且它可能會擦除硬盤驅動器。

相反,得到一個顯式的迭代器。呼叫erase,不remove和迭代器設置爲erase返回值來繼續迭代(返回值:「迭代器的最後一個被刪除的元素之後」)

+0

正如我在回覆erip的評論中所說的那樣,一旦有人告訴我迭代器失效,它就會提示。感謝'erase'方法的繼續迭代! –

1

list::remove

迭代器的有效性:迭代器,指針和引用該函數刪除元素的引用無效。

基於範圍的循環在內部使用迭代器,所以你做了什麼使迭代器無效,因此你期望的行爲不是你所期待的。

std::remove不同,它只是將元素移動到容器的末尾,並返回指向第一個指針的指針「去除」 - 因此需要着名的erase-remove-idiom-list :: remove實際調用析構函數。

0

在第一次迭代,你成功取出第一個元素,沿連接std :: list的第一個元素和第二個元素。所以它在第二次迭代中遇到了問題,因爲for循環無法將指向具有未定義值的已刪除元素的auto wholeNumber設置爲std :: list的第二個元素。