如何删除std::vector内的element?(使用for loop) (中级)
初学者若想要删除std::vector内的element,第一个想到的就是用for loop,若该iterator的值是我要删的,就erase
以上的程序,compile可过,但run-time无法执行,为什么呢?若用debug的watch观察,发现iter被erase后,该iter会指向一个不可预期的地址,导致++iter错误,若要用for loop,必须改成以下写法
1// Compile OK, but run-time error!!
2for(std::vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter) {
3 if (*iter == 8) {
4 ivec.erase(iter);
5 }
6}
2for(std::vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter) {
3 if (*iter == 8) {
4 ivec.erase(iter);
5 }
6}
以上的程序,compile可过,但run-time无法执行,为什么呢?若用debug的watch观察,发现iter被erase后,该iter会指向一个不可预期的地址,导致++iter错误,若要用for loop,必须改成以下写法
1/*
2(C) OOMusou 2006 http://oomusou.cnblogs.com
3
4Filename : VectorFindAndEraseByForLoop.cpp
5Compiler : Visual C++ 8.0
6Description : Demo how to erase iterator by For Loop.
7Release : 11/14/2006
8*/
9#include <iostream>
10#include <vector>
11
12int main() {
13 const int iaSize = 11;
14 int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};
15
16 std::vector<int> ivec;
17 ivec.insert(ivec.end(), ia, ia + iaSize);
18
19 // Compile OK, but run-time error!!
20 //for(std::vector<int>::iterator iter = ivec.begin();
21 // iter != ivec.end(); ++iter) {
22 // if (*iter == 8) {
23 // ivec.erase(iter);
24 // }
25 //}
26
27 // Compile OK, run-time OK!!
28 for(std::vector<int>::iterator iter = ivec.begin();
29 iter != ivec.end(); ++iter) {
30 if (*iter == 8) {
31 --(iter = ivec.erase(iter));
32 }
33 }
34
35 // cout the result
36 for(std::vector<int>::const_iterator iter = ivec.begin();
37 iter != ivec.end(); ++iter) {
38
39 std::cout << *iter << std::endl;
40 }
41
42 return 0;
43}
2(C) OOMusou 2006 http://oomusou.cnblogs.com
3
4Filename : VectorFindAndEraseByForLoop.cpp
5Compiler : Visual C++ 8.0
6Description : Demo how to erase iterator by For Loop.
7Release : 11/14/2006
8*/
9#include <iostream>
10#include <vector>
11
12int main() {
13 const int iaSize = 11;
14 int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};
15
16 std::vector<int> ivec;
17 ivec.insert(ivec.end(), ia, ia + iaSize);
18
19 // Compile OK, but run-time error!!
20 //for(std::vector<int>::iterator iter = ivec.begin();
21 // iter != ivec.end(); ++iter) {
22 // if (*iter == 8) {
23 // ivec.erase(iter);
24 // }
25 //}
26
27 // Compile OK, run-time OK!!
28 for(std::vector<int>::iterator iter = ivec.begin();
29 iter != ivec.end(); ++iter) {
30 if (*iter == 8) {
31 --(iter = ivec.erase(iter));
32 }
33 }
34
35 // cout the result
36 for(std::vector<int>::const_iterator iter = ivec.begin();
37 iter != ivec.end(); ++iter) {
38
39 std::cout << *iter << std::endl;
40 }
41
42 return 0;
43}
vector.erase()删除iterator后,会传回下一个iterator的pointer,若在由for loop的++iter,则会少考虑了被删除后的下一个iterator,故需加上--,将iterator往前移,移到被删除的iterator的前一个iterator,这样for loop的++iterator才会考虑到被删除的下一个iterator。
为了证明这个方法可行,而不是只适用于vector(因为常发现vector可跑的程序,在其它container却不能跑),特别将原程序改成list,证明此法正确。
1/*
2(C) OOMusou 2006 http://oomusou.cnblogs.com
3
4Filename : ListFindAndEraseByForLoop.cpp
5Compiler : Visual C++ 8.0
6Description : Demo how to erase iterator by For Loop.
7Release : 11/14/2006
8*/
9#include <iostream>
10#include <list>
11
12int main() {
13
14 std::list<int> ilist;
15 for(int i = 0; i != 10; ++i) {
16 ilist.push_back(i);
17 }
18
19 // Compile OK, but run-time error!!
20 //for(std::list<int>::iterator iter = ilist.begin();
21 // iter != ilist.end(); ++iter) {
22 // if (*iter == 8) {
23 // ilist.erase(iter);
24 // }
25 //}
26
27 for(std::list<int>::iterator iter = ilist.begin();
28 iter != ilist.end(); ++iter) {
29 if (*iter == 8) {
30 --(iter = ilist.erase(iter));
31 }
32 }
33
34 // cout the result
35 for(std::list<int>::const_iterator iter = ilist.begin();
36 iter != ilist.end(); ++iter) {
37
38 std::cout << *iter << std::endl;
39 }
40
41 return 0;
42}
2(C) OOMusou 2006 http://oomusou.cnblogs.com
3
4Filename : ListFindAndEraseByForLoop.cpp
5Compiler : Visual C++ 8.0
6Description : Demo how to erase iterator by For Loop.
7Release : 11/14/2006
8*/
9#include <iostream>
10#include <list>
11
12int main() {
13
14 std::list<int> ilist;
15 for(int i = 0; i != 10; ++i) {
16 ilist.push_back(i);
17 }
18
19 // Compile OK, but run-time error!!
20 //for(std::list<int>::iterator iter = ilist.begin();
21 // iter != ilist.end(); ++iter) {
22 // if (*iter == 8) {
23 // ilist.erase(iter);
24 // }
25 //}
26
27 for(std::list<int>::iterator iter = ilist.begin();
28 iter != ilist.end(); ++iter) {
29 if (*iter == 8) {
30 --(iter = ilist.erase(iter));
31 }
32 }
33
34 // cout the result
35 for(std::list<int>::const_iterator iter = ilist.begin();
36 iter != ilist.end(); ++iter) {
37
38 std::cout << *iter << std::endl;
39 }
40
41 return 0;
42}
其实这并不是建议的方式,只是demo若还是要用for loop写,该怎么改成可以执行的程序,但可以发现程序相当的『丑』,修修补补的痕迹非常明显,正规的作法该用find()这个generic algorithm找到要删除的iterator后,直接删除,请参阅如何删除std::vector内的element?(使用find) (初级)
See Also
如何删除std::vector内的element?(使用find) (初级)