vector迭代器失效分析

1.迭代器简介

迭代器(iterator)是STL库的一大组件,它可以让我们更为便利的对容器中的元素进行操作。从使用层面上讲,它的操作十分类似于指针。例如我们可以使用解引用操作,取得迭代器位置的元素。或者是自增操作,让迭代器指向下一个元素。

在vector容器中,迭代器的底层实际就是指针变量。因为vector本身在物理层面就是线性结构,所以可以很好的和指针的操作兼容。

但是,我们在使用迭代器时,常常会遇到迭代器失效的情况。一旦迭代器失效,就可能出现各种意想不到的错误,下面,我们就来分析迭代器失效的原因,以及迭代器失效的解决办法。

2.insert操作导致的迭代器失效

我们在使用insert函数对vector容器进行操作时,需要进行如下调用:

iterator insert (iterator position, const value_type& val);

而迭代器失效就是指传入的position迭代器在经过insert操作后变得不可用。

举个例子:

int main()
{
	vector v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);//v有三个元素 1,2,3

	vector::iterator it = find(v.begin(),v.end(),3);
    //找到3并用迭代器it记录该位置

	v.insert(it, 8);//在3的位置插入一个8
	cout << *it << endl;//输出it位置的元素
	return 0;
}

运行上面这段代码,我们会发现程序崩溃了。这是为什么呢?

因为在insert时,vector可能需要进行扩容,而扩容的本质是new一块新的空间,再将数据迁移过去。而我们知道,迭代器的本质是指针,而插入后,若vector扩容,则原有的数据被释放,指向原有数据的迭代器就成了野指针,所以迭代器失效了。

而解决的办法很简单,insert函数提供了返回值,这个返回值是指向插入之后的val的迭代器。我们只需要保存返回的迭代器,并使用这个新的迭代器即可。

另外,插入操作会导致所有的迭代器失效,因为所有的数据都被迁移,原空间的所有迭代器都成了野指针。

3.erase操作导致的迭代器失效

使用erase函数删除指定迭代器位置的元素,需要进行如下调用:

iterator erase (iterator position);

下面我们用一个例子来说明erase产生的迭代器失效:

int main()
{
	vector v;
	v.push_back(1);
	v.push_back(1);
	v.push_back(1);
	v.push_back(1); //此时v的元素为 1,1,1,1
	vector::iterator it0 = v.begin();
	vector::iterator it1 = v.begin() + 1;
	vector::iterator it2 = v.begin() + 2;
	vector::iterator it3 = v.begin() + 3;//四个迭代器分别指向下标为0 1 2 3的元素
	v.erase(it2);//erase掉it2迭代器位置的元素
	cout << *it0 << endl;
	cout << *it1 << endl;
	cout << *it2 << endl;
	cout << *it3 << endl;//对四个迭代器指向的元素进行输出
	return 0;
}

我们逐语句进行调试,会发现,it0和it1的值是可以打出来的,而到了it2,程序就会崩溃。

那么,这是为什么呢?其实,在erase后,VS编译器会判定迭代器失效,因为迭代器位置的元素被删除后,不再指向删除前的元素,所以迭代器失效了。故程序运行到输出it2位置,就崩溃了。

int main()
{
	vector v;
	v.push_back(1);
	v.push_back(1);
	v.push_back(1);
	v.push_back(1); 
	vector::iterator it0 = v.begin();
	vector::iterator it1 = v.begin() + 1;
	vector::iterator it2 = v.begin() + 2;
	vector::iterator it3 = v.begin() + 3;
	v.erase(it2);
	cout << *it0 << endl;
	cout << *it1 << endl;//q去掉了删除it2位置元素的操作
	cout << *it3 << endl;
	return 0;
}

接着,我们把输出it2的语句删除,但是我们运行到输出it3所指向的元素时,程序仍然崩溃了。这是因为,删除操作后,由于删除位置后面的数据都要向前挪一位,导致了删除位置后面的迭代器所指向的元素都发生了变化,所以处于it2位置之后的it3,也在所难免的失效了。

vector迭代器失效分析_第1张图片

解决erase操作导致的迭代器失效的办法也很简单,erase同样会返回一个迭代器,这个迭代器指向了在erase操作前,被删除元素的下一个元素的新位置。所以,我们进行erase操作后,直接使用这个返回的迭代器即可。

你可能感兴趣的:(C++,c++,开发语言)