C++语法学习笔记七: 迭代器及其失效分析、避免迭代器失效

实例代码:


#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct student{
	int num;
}; 

struct conf {
	char itemName[40];
	char itemContect[100];

};


char* getinfo(vector<conf*> & conflist, const char* pitem) {
	for (auto pos = conflist.begin(); pos != conflist.end(); ++pos) {
		if (_stricmp((*pos)->itemName, pitem) == 0) {
			return (*pos)->itemContect;
		}
	}
	return nullptr;
}


int main() {

	//一: 迭代器简介
	//迭代器是一种遍历容器内元素的 数据类型, 这种数据类型感觉有点像指针,我们可以理解为迭代器用来指向容器中的某个元素。
	//通过迭代器,我们就可以读容器中的元素值,读string中的每个字符,HIA可以修改某个迭代器所指向的元素值
	//list map这些容器 尽量用迭代器来访问容器中的元素

	//二: 容器的迭代器类型
	vector<int> iv = { 100, 200, 300 };
	vector<int>::iterator iter;//定义迭代器,也必须是 vector<int>

	//大家在理解的时候,就把整个vector<int>::iterator 理解成一个类型,这种类型就专门应用于迭代器。
	//党我们用这个类型定义一个变量的时候,这个变量就是个迭代器,这里iter这个变量 就是个迭代器

	//三:迭代器begin() / end()操作,反向迭代器rbegin()/rend() 操作
	//begin()/end()用来 返回 迭代类型。rbegin()/rend()用来返回迭代类型。
	//(1) begin()返回一个迭代器类型(大家就理解成返回一个迭代器)
	iter = iv.begin();// 如果容器中有元素,则begin返回的迭代器,指向的是容器中的第一个元素。 相当于iter 指向iv[0];
	//(2) end(); 返回一个迭代器类型(大家就理解成返回一个迭代器);
	iter = iv.end(); // end 返回的迭代器指向的并不是末端元素,而是末端元素的后面,
	//(3) 如果一个容器为空,那么begin()和end()返回的迭代器就相同
	vector<int> iv2;
	vector<int>::iterator iterbegin = iv2.begin();
	vector<int>::iterator iterend = iv2.end();
	if (iterbegin == iterend) {
		cout << "容器iv2为空" << endl;
	}

	//(4) 
	vector<int> iv3 = {100, 200, 300}; //定义一个容器
	for (vector<int>::iterator iter = iv3.begin(); iter != iv3.end(); iter++) {
		cout << *iter << endl; //输出 : 100 200 300
	}

	//rbegin()/rend()  反向迭代器(逆向迭代器)用于从后往前遍历一个容器
	//rbegin(): 返回一个反向迭代器,指向反向迭代器的第一个元素
	//rend():返回一个反向迭代器,指向反向迭代器的最后元素的下一个位置
	for (vector<int>::reverse_iterator riter = iv3.rbegin(); riter != iv3.rend(); riter++) {
		cout << *riter << endl; //输出: 300 200  100
	}

	//四:迭代器运算符
	//(1) *iter: 返回迭代器iter所指向元素的引用。必须要保证这个迭代器指向的是有效的容器元素,
	//		不能指向end(),因为end() 是末端元素的后边,也就是end()指向的是一个不存在的元素
	//iter = iv3.end();
	iter = iv3.begin();
	cout << *iter << endl;  //输出: 100

	//(2) ++iter; iter++; 让迭代器指向容器中下一个元素,已经指向end()的时候你不能再++;
	iter = iv3.begin();
	iter++; //++iter;
	cout << *iter << endl;  //输出: 200
	
	//(3) --iter 和--iter:让迭代器指向容器中的上一个元素。已经指向开头元素,就不能再--
	iter = iv3.end();
	iter--; //--iter;
	cout << *iter << endl;  //输出: 300

	//(4) iter1 == iter2, iter1 != iter2。 判断两个迭代器是否相等。
	//如果两个迭代器指向的是同一个元素,就相等,否则就不等

	//(5) 如何引用结构中的成员
	vector<student> sv;

	student mystu;
	mystu.num = 100;
	sv.push_back(mystu); //把对象mystu赋值到sv容器中

	vector<student>::iterator iterstud;
	iterstud = sv.begin();//指向第一个元素
	cout << (*iterstud).num << endl;
	cout << iterstud->num << endl;

	//五: const_iterator迭代器,const: 常量
	//const_iterator迭代器,表示值不能改变的意思,这里的值不能改变表示这个迭代器指向的元素值不能改变
	//只能从容器中读元素,不能通过这个迭代器改写容器中的元素
	//iterator 是能读能写
	for (vector<int>::const_iterator constIter = iv3.begin(); constIter != iv3.end(); constIter++) {
		//*constIter = 4; //报错
		cout << *constIter << endl; //可以正常读  输出 : 100 200 300
	}

	//(1). cbegin() 和 cend()操作
	//C++ 11 引入的两个新函数cbegin()、cend(),跟begin()、end()类似。cbegin()、cend()返回的都是常量迭代器;c 代表const
	for (auto iter = iv3.cbegin(); iter != iv3.cend(); iter++) {
		//*iter = 4; //报错 , 不能给常量赋值,这说明cbegin返回的是常量迭代器。 
		cout << *iter << endl; //可以正常读  输出 : 100 200 300
	}

	//六: 迭代器失效
	vector<int> vecvalue{ 1,2,3,4,5 };
	//for (auto vecitem : vecvalue){
	//	vecvalue.push_back(888); //在循环中插入数据  导致迭代器失效
	//	cout << vecitem << endl;  //输出数据混乱
	//}

	//在操作迭代器的过程中(使用了迭代器这种循环体),千万不要改变vector容器的容量,也就是不要增加或者删除vector容器中的元素
	//往容器中增加或者从容器中删除元素,这些操作可能也使指向容器元素的指针、引用、迭代器失效。
	//失效就表示不能再带吧任何容器中的元素,一旦使用失效的东西,程序会直接奔溃。

	//(1) 避免迭代器失效1
	auto beg = vecvalue.begin();
	auto end = vecvalue.end();

	while (beg != end) {
		cout << *beg << endl;
		//我们往这个位置插入新值 
		vecvalue.insert(beg, 80); //插入新值,第一个参数为插入位置,第二个参数为插入的元素
		break; //为了防止迭代器失效,插入完毕就break出循环体
		++beg;
	}

	beg = vecvalue.begin();
	end = vecvalue.end();
	while (beg != end) {
		cout << *beg << endl;
		++beg;
	}

	//(2) 避免迭代器失效2
	auto iterea = vecvalue.begin();
	while (iterea != vecvalue.end()) {
		iterea = vecvalue.erase(iterea);
	}

	//(3) 避免迭代器失效3
	vecvalue = { 1,2,3,4,5 };
	while (!vecvalue.empty()){
		auto iter = vecvalue.begin(); //因为不为空,所以返回begin()是没问题。
		vecvalue.erase(iter);//删除该位置上的元素
	}

	//七:范例演示
	//(1) 用迭代器遍历一下string类型数据
	string strt("I Love China!");
	for (auto iter = strt.begin(); iter != strt.end(); ++iter) {
		*iter = toupper(*iter);
	}
	cout << strt << endl;

	//(2) vector 容器常用操作与内存释放
	conf* pconf1 = new conf;
	strcpy_s(pconf1->itemName, sizeof(pconf1->itemName), "ServerName");
	strcpy_s(pconf1->itemContect, sizeof(pconf1->itemContect), "1区");

	conf* pconf2 = new conf;
	strcpy_s(pconf2->itemName, sizeof(pconf2->itemName), "ServerID");
	strcpy_s(pconf2->itemContect, sizeof(pconf2->itemContect), "10000");


	vector<conf*> conflist;
	conflist.push_back(pconf1);  //[0]
	conflist.push_back(pconf2);  //[1]

	//strcpy_s(pconf1->itemName, sizeof(pconf1->itemName), "ServerName123456");

	char* p_tmp = getinfo(conflist, "ServerName");
	if (p_tmp != nullptr) {
		cout << p_tmp << endl;
	}


	//我们要释放内存,自己new的就要自己释放,否则会造成内存泄露;
	std::vector<conf*>::iterator pos;
	for (pos = conflist.begin(); pos != conflist.end();++pos) {
		delete(*pos); //只是释放内存 并没有破坏vector中元素 所以迭代器并不会失效
	}

	conflist.clear(); //这个要不要都行


	system("pause");
	return 0;
}


示意图

在这里插入图片描述
在这里插入图片描述

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值