C++ STL --- vector之迭代器失效

目录

1.什么是迭代器失效?

  (1)文字阐述迭代器失效 

  (2)举例阐述迭代器失效

2.vector哪些操作会导致迭代器失效?

3.如何避免迭代器失效?


        在上一篇关于vector用法的博客中,曾提到过迭代器失效这个话题,但是因为那篇文章主要是用来展示函数用法的,所以单独来谈一下迭代器失效。

        这篇文章的要点只有三点:1.什么是迭代器失效? 2.vector哪些操作会导致迭代器失效? 3.如何避免迭代器失效?

1.什么是迭代器失效?

  (1)文字阐述迭代器失效 

        [1]迭代器的本质就是指针,迭代器失效就是指针失效。

        [2]指针失效:指针指向的空间是非法的。

        [3]指针指向非法空间:指向了被释放的空间 或者 越界访问 。

        是不是很简单,只需要三句话就可以简单阐述迭代器失效。

  (2)举例阐述迭代器失效

        下面来看一个例子更好的理解迭代器失效。

        代码一:这段代码编译的时候就已经报错了,所以为大家截图了调试时的监视窗口。

        原因:it指向初始空间的首元素,尾插元素时空间不足,开辟更大的新空间存储元素,释放旧空间,但此时it仍旧指向已经被释放的旧空间,成为了野指针。在循环中试图对野指针进行解引用导致程序崩溃。

//代码一
#include "iostream"
#include "vector"
using namespace std;

void Test() {
	vector v{ 1,2,3,4 };
	//指向当前空间的首元素
	auto it = v.begin();

	//开辟新空间,拷贝元素释放旧空间
	//此时it仍旧指向旧空间
	v.push_back(5);
	while (it != v.end()) {
		cout << *it;
		it++;
	}
}

int main() {
	Test();
}

        调试代码时的 监视窗口:在监视窗口中可以看到,初始容量是4,尾插时进行了扩容,这也就导致了it成为野指针。

C++ STL --- vector之迭代器失效_第1张图片

C++ STL --- vector之迭代器失效_第2张图片 

        相信通过这个例子大家已经更好的理解了迭代器失效。

2.vector哪些操作会导致迭代器失效?

        a.所有可能会引起扩容的操作都可能会导致迭代器失效。如:resize、reserve、insert、assign、push_back等

        这一点在举例子时已经证明过了,这里就不再赘述了。

        b.指定位置的删除操作--erase。这一点比较难理解。

        首先要知道erase(iterator pos)函数的返回值是被删除元素后一位元素的迭代器。当删除元素后,pos位置之后的元素会往前搬移,没有导致底层空间改变。理论上来说是不是觉得这个函数并不会导致迭代器失效?

        但是:如果pos元素刚好是最后一个元素,删完后pos就刚好是end()的位置,而end()位置并没有元素,那么一旦试图解引用pos就会崩溃。因此vs编译器觉得这样的操作不安全,vs就认为当你使用erase删除了一个元素后,该位置的迭代器就应该按失效处理,不要再使用了。

//代码二
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;

void Test() {
	vector v{ 1,2,3,4 ,5,6,7,8,9,10};
	auto it = v.begin();
	//删除偶数

	while (it != v.end()) {
		if (*it % 2 == 0)
			v.erase(it);
		else
			it++;
	}
} 

int main() {
	Test();
}

3.如何避免迭代器失效?

        解决办法简单粗暴:在所有可能导致迭代器失效的操作之后,如果要使用迭代器,在使用前重新赋值,使其指向新空间。

        既然迭代器可能失效,那么我就在使用前重新赋值,让其指向合法的空间再使用。

        现在来把代码一和二做一点小小的改动,让它们变得安全。

        代码三:将代码一和二放在同一段代码中,在使用之前对其重新赋值。

        使用erase函数后,就用它的返回值重新对迭代器赋值,使它变得安全。

//代码三
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;

void Test1() {
	vector v{ 1,2,3,4 };
	auto it = v.begin();
	v.push_back(5);

	//使用迭代器前对它重新赋值
	it = v.begin();
	while (it != v.end()) {
		cout << *it;
		it++;
	}
}

void Test2() {
	vector v{ 1,2,3,4 ,5,6,7,8,9,10 };
	auto it = v.begin();
	//删除偶数

	while (it != v.end()) {
		if (*it % 2 == 0)
			//因为erase函数返回值是被删除元素后一位元素的迭代器
			//用它的返回值对it进行重新赋值
			it = v.erase(it);
		else
			it++;
	}
}


int main() {
	Test1();
	Test2();
}

你可能感兴趣的:(C++,c++,STL,vector,容器,迭代器失效)