目的
实际开发中,经常用到边遍历边删除的情况,vector/list都会遇到这种情况。
先看看删除函数的用法:
情况
最常犯的错误
执行第一段代码:
void traversalVector1()
{
std::cout << "enter function traversalVector" << std::endl;
std::vector<int> myList = { 11, 22, 24, 33, 44, 55 };
std::vector<int>::iterator iter;
for (auto it = myList.begin(); it != myList.end(); it++) {
if (*it % 2 == 0) { // 如果元素是偶数
myList.erase(it); // 删除元素,迭代器自增
}
}
// 打印剩余的元素
for (const auto& value : myList) {
std::cout << value << " ";
}
std::cout << std::endl;
std::cout << "exit function traversalVector" << std::endl;
}
循环一次it是11:
在执行完到22元素后,再执行it++,就会出现空指针异常,因为在执行22元素时,进行了删除操作,删除操作之后,游标发生了变化,必须用新的游标。
这一个新的游标就是erase返回的游标,就是删除元素的下一个元素的位置。
can’t increment vector iterator past end
删除之后,元素前移了,原来的22的位置,现在成了33的位置,所以22的地址与33的地址是一样的。
正确的用法
void traversalVector2()
{
std::cout <<"enter function traversalVector" << std::endl;
std::vector<int> myList = { 11, 22, 24, 33, 44, 55 };
for (auto it = myList.begin(); it != myList.end(); ) {
if (*it % 2 == 0) { // 如果元素是偶数
it = myList.erase(it); // 删除元素,迭代器自增
}
else {
++it; // 如果元素是奇数,移动到下一个元素
}
}
// 打印剩余的元素
for (const auto& value : myList) {
std::cout << value << " ";
}
std::cout << std::endl;
std::cout << "exit function traversalVector" << std::endl;
}
void traversalList()
{
std::cout << "enter function traversalList" << std::endl;
std::list<int> myList = { 11, 22, 24, 33, 44, 55 };
for (auto it = myList.begin(); it != myList.end(); ) {
if (*it % 2 == 0) { // 如果元素是偶数
it = myList.erase(it); // 删除元素,并获取下一个有效迭代器
}
else {
++it; // 如果元素是奇数,移动到下一个元素
}
}
// 打印剩余的元素
for (const auto& value : myList) {
std::cout << value << " ";
}
std::cout << std::endl;
std::cout << "exit function traversalList" << std::endl;
}
int main()
{
//std::cout << "Hello World!\n";
//traversalVector1();
traversalVector2();
traversalList();
}
运行情况:
总结
上面图就是结合上面例子的分析,这里最为关键的理解就是,iterator是与容器紧密关联的,如果容器发生了变化,原来的iterator就失效了,因为容器可能重新分配空间,所以必须重新获取iterator.
有两种简单的获取方法:
1、和原来的一样,再it = myList.begin();
2、接着循环往下走:it = myList.erase(it);
就是这么简单