从列表容器中删除一个元素
Erasing an element from a list container
我很难理解为什么代码是这样表现的。首先,我阅读了相关的回答材料,仍然发现解释有点超前。所以我想知道是否有人可以用一种简单的方式来解释这个问题。
好,我要从列表中删除元素。
列表包含奇数和偶数的int元素。这部分我理解。下面是我最初编写的代码,用于从列表
中删除奇数for(list<int>::iterator i = lNo.begin(); i != lNo.end(); i++)
{
if(*i%2 == 0 )
{
lNo.erase(i);
}
else
{
cout << " " << *i;
}
}
对于这段代码,程序根本无法编译,我读到一条消息,声明程序必须关闭。
当我写这段代码时,擦除函数工作:
for(list<int>::iterator i = lNo.begin(); i != lNo.end(); i++)
{
if(*i%2 == 0 )
{
i = lNo.erase(i);
}
else
{
cout << " " << *i;
}
}
我只需要理解为什么程序工作时,我的代码I = lNo.erase(I),而不是仅仅lNo.erase(I)?
请给我一个简明扼要的答复。我知道不同的容器有不同的约束,那么我在原始代码中违反了哪个约束呢?
如文档中所述,erase
函数使传入的迭代器无效。这意味着它不能再被使用。该迭代器不能继续循环。
文档还指出,它返回一个迭代器,指向被擦除的元素之后的元素。该迭代器有效,可用于继续操作。
但是请注意,由于它返回一个迭代器,指向被擦除的元素之后的元素,因此不需要对元素进行自增来前进,否则不会检查该元素的奇异性。循环应该考虑到这一点,并且只在没有擦除时才增加。你的第二个代码也不正确。
正确的代码应该是这样的:for(list<int>::iterator i = lNo.begin(); i != lNo.end(); /*NOTHING HERE*/ )
{
if(*i%2 == 0 )
{
i = lNo.erase(i);
}
else
{
cout << " " << *i;
++i; //INCREMENT HERE, not in the for loop
}
}
注意,erase()
擦除该项并返回迭代器到下一项。这意味着,当您擦除时,您不需要在代码中增加i
;相反,您只需要使用erase
的返回值更新i
。
您可以使用erase-remove idiom
作为:
lNo.erase(std::remove_if(lNo.begin(),
lNo.end(),
[](int i) { return i%2 == 0; }),
lNo.end());
现场演示
问题是,您使用的迭代器不期望修改列表的链。所以当你在列表上调用erase()时,链被有效地修改了,所以你的迭代器不再有效。i++语句不再工作了
但是,在第二个版本中,您将迭代器重新赋值给仍然具有完整链接的有效对象,因此i++语句仍然可以工作。
在某些框架中,你有两种迭代器,一种是立即反映底层数据集发生了什么(这是你正在使用的),另一种是无论底层数据集发生了什么,都不会改变它们的链接(所以你不必使用第二个版本的奇怪技巧)。
相关文章:
- lower_bound()返回最后一个元素
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- Lower_bound不适用于具有 3 个元素的向量的最后一个元素
- 检查 2D 网格的某个元素是否与另一个元素共享对角线、水平线或垂直线
- 仅显示链表的最后一个元素
- push_back通过自行创建的对象获取最后一个元素的向量
- 使用 map.end() 访问 map 的最后一个元素
- 如何知道地图中的最后一个元素是否被删除?
- 选择一个元素而不是一个对象的数组的原因
- std::矢量保存 只推送最后一个元素
- 为什么这个选择排序算法仍然切换一个元素,当它已经是其他元素中最小的元素时?
- 反转后不返回最后一个元素
- 如何在新数组较小时创建新数组并将旧数组的最后一个元素复制到新数组中?
- 访问 for_each 函数中的前一个元素
- 在 QListView 中显示最后一个元素
- 从 std::vector 中选择一个元素,而不是给定元素
- C++:在进行切片时对迭代器的约定,特别是对于访问最后一个元素并最终将其删除
- 遍历列表包含排除最后一个元素的内容
- 如何从一个无序集合中获取一个元素