以下这段话来自《C++标准程序库》—第六章STL容器
“vector迭代器失效发生在下列两种情况
(1)使用者在一个较小索引位置上安插和移除操作
(2)由于容量变化而引起内存分配”
要深刻理解这段话并不容易—-
其实这里迭代器失效的两种情况代表了两种不同的失效含义:
1.当在vector中的某一位置安插(v.insert())或移除(v.erase())某个元素时,且当安插操作时,容器还有一定的容量(v.capacity())来容纳这个元素。如此一来,安插和移除操作不会因容器满而重新分配内存。在安插和移除操作后,作用点位置前的元素并没改变,而操作位置后的元素向后或向前移动一位。因此作用点后的各元素迭代器失效。注意此处的失效只是与安插或移位前定义的迭代器的意图出现稍微偏差。例如安插之前定义了一个逆向迭代器,安插后便无法通过该迭代器遍历所有元素(会丢掉一个元素}。
2.首先,我们知道vector实际上是连续存储的动态数组,因此当容器满时,为了保证连续存储需要重新开辟空间并将其原有数组拷贝到新空间,这使得原来空间的迭代器全部失效。此处的失效会在调试时出现debug assertion failed错误,这是由访问一个野指针而引起。注意vector为其分配内存的机制为:每次当容器满而重新分配内存时,都会分配比所需内存多的空间,因此,大多数安插和移除元素并不会发生内存的重新分配。这在一定程度上优化了vector的效率,避免了每次插入都进行内存重新分配这一耗时的操作。但是,尽管如此,我们也应坚决杜绝使用安插操作前定义的迭代器。
下面通过一个例子来说明迭代器失效的这两种情况。。。
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v;
cout << v.size() << " " << v.capacity() << " " << endl;//空vector
for (int i = 0;i < 10; i++)
v.push_back(i);
cout << "first addr: " << &(*v.begin()) << endl;
cout << "size = " << v.size() << " capacity = " << v.capacity() << endl;//size = 10 capacity = 13
cout << "--------------------" << endl;
//第一种情况:insert一个元素(在容量足够的情况下并不会重新分配内存)【该失效仅仅是无法使用该迭代器遍历或所指向的元素改变了】
vector<int>::iterator it_begin = v.begin();//插入前定义一个迭代器,指向第一个元素
vector<int>::iterator it_end = v.end()-1;//插入前定义一个迭代器,指向最后一个元素
v.insert(v.begin()+1, 1);//在第二个元素位置插入1
cout << "插入一个元素后:" << endl;
cout << "first addr: " << &(*v.begin()) << endl;//首元素地址未变
cout << "size = " << v.size() << " capacity = " << v.capacity() << endl;//size = 10 capacity = 13
cout << *it_begin << endl;//未失效,仍然打印出第一个元素0
cout << *it_end << endl;//失效,打印出了9的前一个元素8(并未出现错误,但这仍是迭代器失效)
cout << "--------------------" << endl;
//此时size=11 capacity=13,紧接着再插入两个元素
cout << "再插入两个元素:" << endl;
v.push_back(10);
v.push_back(11);
cout << "first addr: " << &(*v.begin()) << endl;//首元素地址未变
cout << "size = " << v.size() << " capacity = " << v.capacity() << endl;//size = 13 capacity = 13
cout << "vector 满了" << endl;
cout << "--------------------" << endl;
//接下来再insert或push_back一个元素均会出现内存的重新分配。均会造成先前定义的迭代器失效【该失效会出错,访问野指针的内存】
//第二种情况:push_back一个即将重新分配内存的vector[insert()也会出现同样的问题]
vector<int>::iterator iter = v.begin();//内存重新分配前定义一个迭代器
v.push_back(12);
cout << "再插入一个元素内存重新分配:" << endl;
cout << "first addr: " << &(*v.begin()) << endl;//内存重新分配,首元素地址改变了,容量也多分配了几个
cout << "size = " << v.size() << " capacity = "<< v.capacity() << endl;//size = 14 capacity = 19
cout << *iter << endl;//当重新分配内存后再调用重新分配内存前定义的迭代器,便会发生debug assertion failed错误
cout << "--------------------" << endl;
for (vector<int>::iterator it = v.begin();it != v.end(); ++it)
cout << *it << " ";
return 0;
}
可以看到程序在42行出现了错误:
屏蔽掉42行后运行结果如下:
注:
debug assertion failed是一个经常会遇见的一个调试错误。发生这种错误主要有两种情况:
1.就是上述第二种失效的情况,程序试图去访问一个野指针所指向的内存。
2.内存泄漏:动态分配的内存忘记释放,而且,程序不断调用动态内存分配的程序快,造成内存泄漏的堆积,这会最终消耗尽系统所有的内存。