C++ vector容器遍历并删除元素
在使用C++ vector的迭代器遍历并删除元素时,存在一些不注意的误区,这里特此记录。
在使用迭代器遍历vector元素时,错误的删除方法:
vector<int>::iterator it = vec.begin(); for (; it != vec.end();) { vector<int>::iterator tmpit = it; it++; vec.erase(tmpit); }
正确的删除方法:
vector<int>::iterator it = vec.begin(); for (; it != vec.end();) { it = vec.erase(it); }
一个例子:
vector<int> vec; for (int i = 0; i < 20; ++i) { vec.push_back(i + 1); } for (int i = 0; i < vec.size(); ++i) { cout << vec[i] << " "; } cout << endl; vector<int>::iterator it = vec.begin(); for (; it != vec.end();) { cout << (*it) << endl; if ((*it) % 2 == 1) { vector<int>::iterator tmp = it; it = vec.erase(tmp); } else { it++; } } for (int i = 0; i < vec.size(); ++i) { cout << vec[i] << " "; } cout << endl;
输出结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 3 5 7 9 11 13 15 17 19
符合预期!
当使用以上错误的删除方式时,
vector<int> vec; for (int i = 0; i < 20; ++i) { vec.push_back(i + 1); } for (int i = 0; i < vec.size(); ++i) { cout << vec[i] << " "; } cout << endl; vector<int>::iterator it = vec.begin(); for (; it != vec.end();) { cout << (*it) << endl; if ((*it) % 2 == 0) { vector<int>::iterator tmp = it; it++; vec.erase(tmp); } else { it++; } } for (int i = 0; i < vec.size(); ++i) { cout << vec[i] << " "; } cout << endl;
输出结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 4 6 8 10 12 14 16 18 20 20 Segmentation fault
可以看出,迭代器it的访问已经错乱了。
需要说明的是,vector错误的遍历删除方式,在map中是正确的写法!
重要:vector的erase函数会使迭代器失效,因此,在遍历时使用erase函数后,旧的迭代器就不能再使用了!
看下面一个例子:
vector<int> vec; vec.push_back(1); vec.push_back(2); vector<int>::iterator it = vec.begin(); for (; it != vec.end();) { cout << (*it) << endl; if ((*it) % 2 == 1) { vector<int>::iterator tmp = it; cout << "before erase:" << (*tmp) << endl; it = vec.erase(tmp); cout << "after erase:" << (*tmp) << endl; } else { it++; } }
输出结果为:
1 before erase:1 after erase:2 2
可以看到,erase前的tmp跟it一样,erase之后,tmp并不是旧的it值。
所以万不可在erase之后去访问旧的迭代器!