首先简单介绍一下vector。
vector的实现一般是用一个动态分配的数组,vector中的元素连续地存放在这个数组中,并且vector具有动态扩展容易空间的功能,当数组的空间不够时,vector对象会自动new分配一块更大的空间,使用赋值运算符“=”将原有的数据分别赋值到新的空间中,并将原有的空间释放。
下面来看vector::reserve()。
若s是一个vector实例,n是一个整型数据,则s.reserve(n)可解释为:若当前向量容器 s 的容量大于或等于n,什么也不做,否则扩大 s 的容量,使得 s 的容量不小于n。这个函数的实用性在于:如果在准备向向量容器中插入大量数据之前能够粗略估计出插入元素之后向量容器的大小,就可以在插入前使用reserve函数来确保这部分空间被分配,避免在插入过程中多次重新分配空间,提高效率。
如果reserve函数引起了向量容量的扩展,那么执行此函数之前所获得的一切迭代器和指向向量元素的指针、引用都会失效,这是因为空间被重新分配了,元素的内存地址发生了改变。
让我们来分析一下代码。
#include<iostream> #include<vector> using namespace std; int main() { vector<int> v; vector<int>::iterator iter; cout << v.capacity() << endl; v.push_back(10); v.push_back(19); iter = v.begin(); v.reserve(10); cout << v.capacity() << endl; cout << v.size() << endl; cout << v[0] << endl; cout << *iter << endl; iter = v.erase(iter); cout << *iter << endl; return 0; }
main()函数中代码第六行iter获得了一个迭代器,接下来一行执行了reverse函数使得这个迭代器失效。第十一行使用了*iter,虽然iter已经失效,但此行*iter的输出是10。这个是怎么回事呢?原因是:这个10是原先地址空间中的那个值,也就是说此时的iter已经是一个野指针了,但是它指向的地址是之前向量容器所占的地址空间。要注意的是,之前的地址空间是已经被释放了的,所以第十二行erase函数调用时会出错的。
通过上面的例子,我们知道了reserve函数的调用可能会引起迭代器的失效。在元素的插入过程中,可能因为reserve函数调用导致迭代器全部失效,此外,插入位置之后的迭代器和指针、引用会失效,因为这些元素被移动了,而插入位置之前的元素不会有影响。所谓“失效”,是指继续使用这样的迭代器或指针,结果是不确定的。
所以,以后使用reserve函数时,留心下迭代器是否失效。