先写总结
迭代器失效是地址变动引起的,地址变动由1、重新分配内存。2、由删除或插入元素导致的前移或后移。引发!
再就是要注意insert和erase返回的迭代器位置。
插入insert元素引发迭代器失效
1、当 vector 的size()==caparity()
时,再插入元素会导致 vector 重新分配内存,进而使迭代器失效!!!
2、当 vector 的size()<caparity()
时,再vector中间插入元素,因为vector的空间是连续的,虽然这时容量足够大,不会引发重新分配内存,但也会导致插入位置之后的元素向后移动,导致插入位置之后的迭代器失效!!!
总之,向vector中添加元素,若存储空间被重新分配,则指向vector的迭代器、指针和引用都会失效。若存储空间未重新分配,指向插入位置之前的元素的迭代器、指针和引用仍有效,但指向插入位置之后元素的迭代器、指针和引用将会失效。
删除erase元素引发迭代器失效
vector使用erase时,指向被删元素之前元素的迭代器、引用和指针仍然有效,但指向删除位置之后元素的迭代器、指针和引用将会失效,注意:当我们删除元素时,尾后迭代器总是失效的。
编写改变容器的循环程序例子
添加/删除vector,string或deque元素的循环程序必须考虑迭代器、引用和指针可能失效的问题。程序必须保证每个循环中都更新迭代器、引用和指针。如果循环中调用的是insert或erase,那么更新迭代器很容易。这些操作都返回迭代器。
#include <cstdio>
#include <vector>
using namespace std;
int main(){
vector<int> v;
for(int i=1;i<=10;i++){
v.push_back(i);
}
vector<int>::iterator it=v.begin();
while(it!=v.end()){
if(*it%2){
it=v.insert(it,*it);//复制当前
it+=2;//向前移动跳过当前元素以及插入到它之前的元素
}
else{
it=v.erase(it);//删除偶元素
//不应该向前移动,it指向删除之后的元素
}
}
for(int i=0;i<v.size();i++){
printf("%d ",v[i]);
}
printf("\n");
return 0;
}
关键是caparity的变化是挺频繁的,尤其是小数据量的时候
看一个代码:
#include <cstdio>
#include <vector>
using namespace std;
int main(){
vector<int> v;
for(int i=1;i<=100;i++){
int a=v.capacity();
v.push_back(i);
int b=v.capacity();
printf("%lld ",v.capacity());
if(a!=b){
printf("begin: %p ",v.begin());
}
}
return 0;
}
以前以为是自动延长,结果是直接搬家!!!看下输出结果
1 begin: 0000000000bf13f0 2 begin: 0000000000bf1410 4 begin: 0000000000bf13f0 4 8 begin: 0000000000bf1410 8
8 8 16 begin: 0000000000bf1440 16 16 16 16 16 16 16 32 begin: 0000000000bf1490 32 32 32 32 32 32 32 32 32 32
32 32 32 32 32 64 begin: 0000000000bf1520 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64
64 64 64 64 64 64 64 64 64 128 begin: 0000000000bf1630 128 128 128 128 128 128 128 128 128 128 128 128 128
128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128 128
begin 的地址每次搬家后就没有相同的,所以为了保险起见,每次插入元素之后,迭代器要it = v.begin();
vector的insert函数的用法
1、v.insert(p,t);
在p位置之前插入值t,返回指向t的迭代器。
2、v.insert(p,n,t);
在p位置之前插入n个值t,返回指向第一个t的迭代器。
3、 v.insert(p,b,e);
b,e是其他容器的迭代器,将迭代器b和e指定的范围内的元素插入到迭代器p指向的元素之前。b和e不能指向v中的元素。返回指向新添加的第一个元素的迭代器;若范围为空,则返回p
vector的erase函数的用法
1、v.erase(p);
删除迭代器p所指定的元素,返回一个指向被删元素之后元素的迭代器,若p指向尾元素,则返 回尾后(off-the-end)迭代器。
2、v.erase(b,e);
删除迭代器b和e所指定范围内的元素。返回一个指向最后一个被删元素之后的元素的迭代器,若 e本身就是尾后迭代器,则函数也返回尾后迭代器
3、v.clear();
删除v中的所有元素,返回void
补充deque双端队列
删除deque中除首尾位置之外的任何元素都会使所有的迭代器、引用和指针失效。