[英]Don't understand results of std::remove in C++ STL
我正在閱讀Josuttis的“ C ++標准庫,第二版”。 在6.7.1節中,作者解釋說,下面給出的代碼將產生意外的結果。 我仍然不了解std::remove()
功能,以及為何得到這種奇怪的結果。 (盡管我了解到您需要使用std::erase()
才能真正刪除元素,實際上最好使用list::erase()
而不是std::remove()
和`std ::的組合去掉())。
list<int> coll;
// insert elements from 6 to 1 and 1 to 6
for (int i=1; i<=6; ++i) {
coll.push_front(i);
coll.push_back(i);
}
// print
copy (coll.cbegin(), coll.cend(), // source
ostream_iterator<int>(cout," ")); // destination
cout << endl;
// remove all elements with value 3
remove (coll.begin(), coll.end(), // range
3); // value
// print (same as above)
結果是
pre: 6 5 4 3 2 1 1 2 3 4 5 6
post: 6 5 4 2 1 1 2 4 5 6 5 6 (???)
此說明應有幫助:
通過以使要擦除的元素被覆蓋的方式移動范圍內的元素來完成刪除。 保留了剩余元素的相對順序,並且容器的物理大小未更改。 指向范圍的新邏輯端和物理端之間的元素的迭代器仍然是可取消引用的,但是元素本身具有未指定的值。 在調用remove之前,通常會先調用容器的擦除方法,該方法將擦除未指定的值並減小容器的物理大小以匹配其新的邏輯大小。
請注意, std::remove()
的返回值是表示新end的迭代器。 因此,在此新端和舊端調用std::erase()
將釋放您的多余空間。
std::remove
實際上並不會縮短列表。 它不能-因為它只獲得迭代器,而不是容器本身。
它所做的是復制剩余的值,以便您可以在容器的開頭獲取它們。 但是容器的最后元素(在您的情況下-最后兩個:“ 5”和“ 6”)實際上仍然存在。
使用std::remove
您必須縮短自己的容器以刪除其余的“垃圾”副本。
引用每個人最喜歡的c ++網站 :
該函數不能更改包含元素范圍的對象的屬性(即,它不能更改數組或容器的大小):刪除是通過將比較等於val的元素替換為下一個不等於val的元素來完成的,並通過將迭代器返回到應該被視為其新的過去元素的元素來發出縮短范圍的新大小的信號。
因此std::remove
不會更改列表的大小。 它刪除匹配的元素,並返回一個代表列表新結尾的迭代器。 要實際刪除無關的元素,您需要執行以下操作:
auto it = remove(coll.begin(), coll.end(), 3);
coll.erase(it, coll.end());
您要求算法刪除“ 3”元素。 因此,在枚舉容器時,如果從中間刪除了某些內容,則算法會移動內容。 在您的情況下,這種移位發生了2次,這就是為什么您在結尾處看到“ 5 6”元素的原因(因為實際的末尾已移至2個項目)。 然后,“ std :: erase”將解決尾巴僵屍的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.