C++中迭代器

本文详细介绍了迭代器的概念及其在C++中的应用,包括如何定义和使用迭代器、不同类型的迭代器如反向迭代器和const_iterator迭代器,以及迭代器运算符的使用。此外,还探讨了迭代器失效的问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、迭代器简介

  迭代器是一种遍历容器内元素的数据类型,这种数据类型有点像指针,理解时候可以理解为迭代器用来指向容器中的某个元素。
vector可以用[]来访问,但是更常用的访问方式是用迭代器。
通过迭代器,我们可以读容器中的元素值,读string中的每个字符,还可以修改某个迭代器所指向的元素值。
一般有容器都会有相关的迭代器list、map等。

二、容器的迭代器类型

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

理解时候可以把整个vector::iterator理解成一个类型,这个类型专门应用于迭代器。
当我们用这个类型定义一个变量时,这个变量就是个迭代器,这里iter这个变量就是个迭代器
三、迭代器begin()/end()操作,反向迭代器rbegin()/rend()操作
  begin()/end()用来返回迭代类型.rbegin()/rend()一样。

iter = iv.begin();//如果容器中有元素则begin返回的迭代器指向容器中第一个元素
iter = iv.end();//end返回末尾元素的后面一个元素

在这里插入图片描述
如果是一个空容器,那么begin()和end()返回的迭代器就相同。
用迭代器来遍历容器

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

using namespace std;
int main()
{
	vector<int> value{1,2,3,4};
	
	for (vector<int>::iterator iter = value.begin(); iter != value.end(); iter++)
	{
		cout << *iter << endl;
	}

	return 0;
}

结果

1
2
3
4

逆向迭代器:从后往前访问
在这里插入图片描述
rbegin():返回一个反向迭代器指向反向迭代器的第一个元素
rend();返回一个反向迭代器指向反向迭代器的最后一个元素的下一个位置(容器最开始元素的前一个位置)

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

using namespace std;
int main()
{
	vector<int> value{1,2,3,4};
	
	for (vector<int>::reverse_iterator riter = value.rbegin(); riter != value.rend(); riter++)
	{
		cout << *riter << endl;
	}

	return 0;
}

结果

4
3
2
1

四、迭代器运算符
*iter:返回迭代器iter所指向元素的引用。必须要保证这个迭代器指向是有效的容器元素,不能指向end(),因为end()是末端元素后边(不存在的一个元素)riter同理。
++iter;iter++;–iter;iter–;都遵循以上原则(不能指向不存在的元素)

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

using namespace std;

struct student
{
	int num;
};

int main()
{
	vector<student> sv;
	student mystu;
	mystu.num = 100;
	sv.push_back(mystu);//把对象mystu复制到sv容器中

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

五、const_iterator迭代器
const_iterator迭代器表示迭代器指向的值不能改变,只能从迭代器中读元素。(iterator能读能写)


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

using namespace std;

int main()
{
	vector<int> iv{1,2,3,4};
	vector<int>::const_iterator iter;

	for (iter = iv.begin(); iter != iv.end(); iter++)
	{
		cout << *iter << endl;
	}
	
	return 0;
}

结果

1
2
3
4

如果是const vector iv{1,2,3,4};常量容器的话就必须用const_iterator来迭代。
5.1cbegin()和cend()操作
c++11引入的两个新函数cbegin()和cend(),跟begin,end类似。cbegin,cend,返回的都是常量迭代器

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

using namespace std;

int main()
{
	vector<int> iv{1,2,3,4};

	for (auto iter = iv.cbegin(); iter != iv.cend(); iter++)
	{
		cout << *iter << endl;
	}
	
	return 0;
}

与上面结果一样,既然返回的是常量迭代器那么与const_iterator一样不能进行赋值操作。
六、迭代器失效
回顾一下学习容器时的失效问题

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

using namespace std;

int main()
{
	vector<int> iv{1,2,3,4};

	for (auto vecitem: iv)
	{
		iv.push_back(88);
		cout << vecitem << endl;
	}
	
	return 0;
}
/*
	for(auto beg = iv.begin(), end = iv.end();beg != end; ++beg)
	{
		iv.push_back(88);
		cout << *beg <<endl;
	}
*/

结果

1
-572662307
-572662307
-572662307

注:在迭代器遍历时进行增/删操作与注释内容是等价的,在操作迭代器过程中,千万不要改变vector容器容量,也就是不要进行增删操作。增加或者删除操作可能会使指向容器的元素指针、引用、迭代器失效。程序可能直接崩溃。如果要进行增加或者删除操作要立即退出去。

for (auto beg = iv.begin(), end = iv.end(); beg != end; ++beg)
{
	iv.push_back(88);
	break;
}

for (auto beg = iv.begin(), end = iv.end(); beg != end; ++beg)
{
	iv.push_back(88);
	cout << *beg << endl;
}

如果想一直插入一定要做好处理,最好是做完操作立即break;

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

using namespace std;

int main()
{
	vector<int> iv{1,2,3,4};

	auto beg = iv.begin();
	int icount=0;
	while (beg != iv.end())//每次更新end防止end失效
	{
		beg = iv.insert(beg, icount++);//insert参数1插入位置,参数2插入元素
		if (icount > 10)
			break;
		++beg;
	}
	beg = iv.begin();
	auto end = iv.end();
	while (beg != end)
	{
		cout << *beg << endl;
		++beg;
	}

	return 0;
}
0
1
2
3
4
5
6
7
8
9
10
1
2
3
4

在程序结束前我们可能会释放掉容器里面内容看如下代码(错误的方法)

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

using namespace std;

int main()
{
	vector<int> iv{1,2,3,4};

	auto beg = iv.begin();
	for (auto iter = iv.begin(); iter != iv.end(); ++iter)
	{
		iv.erase(iter);//erase:移除iter位置上的元素,返回下一个元素位置
	}

	return 0;
}

当这段程序执行时直接崩溃,不用想,问题出在迭代器上,正确做法如下

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

using namespace std;

int main()
{
	vector<int> iv{1,2,3,4};

	auto iter = iv.begin();
	while (iter != iv.end())
	{
		iter = iv.erase(iter);
	}
/*
while (!iv.empty())//判断是否为空
{
	auto iter = iv.begin();//因为不为空,所以返回begin没问题
	iv.erase(iter);//删除位置上的元素
}
*/
	return 0;
}

以上两种方法是一个一个清空,直接清空也可以使用iv.clear();方法
七、范例演示
7.1、用迭代器变量一下string类型数据

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

using namespace std;

int main()
{
	string str("I Love China!");

	for (auto iter = str.begin(); iter != str.end(); ++iter)
	{
		*iter = toupper(*iter);//转成大写
	}
	cout << str << endl;

	return 0;
}
I LOVE CHINA!

7.2vector容器常用操作与内存释放

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

using namespace std;

struct conf
{
	char itemname[40];
	char itemcontent[100];
};

char *getinfo(vector<conf *>&conflist, char *pitem)//返回字符串
{
	for (auto iter = conflist.begin(); iter != conflist.end(); ++iter)
	{
		if (_stricmp((*iter)->itemname, pitem) == 0)//根据名字返回内容
		{
			return (*iter)->itemcontent;
		}
	}
	return nullptr;//没有找到返回空
}

int main()
{
	//ServerName = 1区//表示服务器名称
	//ServerID =1000//表示服务器ID
	conf *pconf1 = new conf;
	strcpy_s(pconf1->itemname, sizeof(pconf1->itemname), "ServerName");
	strcpy_s(pconf1->itemcontent, sizeof(pconf1->itemcontent), "1区");

	conf *pconf2 = new conf;
	strcpy_s(pconf2->itemname, sizeof(pconf2->itemname), "ServerID");
	strcpy_s(pconf2->itemcontent, sizeof(pconf2->itemcontent), "1000");

	vector<conf *> conflist;
	conflist.push_back(pconf1);
	conflist.push_back(pconf2);

	char *p_temp = getinfo(conflist, "ServerName");
	if (p_temp != nullptr)
	{
		cout << p_temp << endl;//1区
	}
	//自己new的自己释放,否则会有内存泄漏
	std::vector<conf *>::iterator pos;
	for(pos = conflist.begin(); pos != conflist.end(); ++pos)
	{
		delete (*pos);//删除图中蓝色内存,容器里面指向的内存无效了
	}

	conflist.clear();//列表指针指向的内存释放掉了,把列表也清空一下

	return 0;
}

在这里插入图片描述

<think>嗯,用户问的是C++迭代器的种类。我需要先回忆一下相关知识,确保自己记得正确。记得迭代器主要分为五类,对吧?输入、输出、前向、双向和随机访问迭代器。它们按照功能从弱到强排列,不同的容器支持不同类型的迭代器。 首先,输入迭代器,只能单向读取,比如istream。输出迭代器只能单向写入,比如ostream。然后前向迭代器可以多次读写,但只能向前移动,像单链表。双向迭代器在此基础上还能后退,比如list或set的迭代器。最强的随机访问迭代器,支持任意位置的跳转,vector和deque是这样的。 用户可能想知道每种迭代器的具体用途和区别,以及对应的容器例子。可能还需要解释它们支持的操作,比如随机访问迭代器支持加减运算,而双向只能自增自减。有没有遗漏的地方?比如C++17中的连续迭代器,或者sentinel之类的?不过用户可能只需要基本分类,暂时不用深入高级内容。 另外,需要检查是否有混淆迭代器类别和具体容器的关系。例如,vector是随机访问,而list是双向。可能还要举例说明不同迭代器支持的操作,比如输入迭代器只能读一次,而前向可以多次。有没有常见的错误需要指出?比如试图对list进行+1操作,这会导致错误,因为它不支持随机访问。 用户可能的背景是正在学习STL,需要理解不同迭代器的能力,以便正确使用算法。例如,sort需要随机访问迭代器,所以不能用于list。这时候需要选择合适的容器或方法。 最后,总结时要强调迭代器类别如何影响算法的选择和使用,确保用户明白分类的重要性和应用场景。语言要简洁明了,用例子帮助理解。</think>在 C++ 中,迭代器(Iterator)是用于遍历容器(如 `vector`、`list`、`map` 等)中元素的对象,类似于指针的行为。根据功能强弱,迭代器分为以下 5 种类别,支持不同的操作: --- ### 1. **输入迭代器(Input Iterator)** - **功能**:只能单向移动(向前),且只能读取元素(不可修改)。 - **支持的操作**:`++`(前置/后置递增)、`*`(解引用)、`==`/`!=`(比较)。 - **典型应用**:一次性遍历(如从文件/网络流读取数据)。 - **示例**:`istream_iterator`(用于输入流)。 --- ### 2. **输出迭代器(Output Iterator)** - **功能**:只能单向移动(向前),且只能写入元素(不可读取)。 - **支持的操作**:`++`(前置/后置递增)、`*`(解引用赋值)。 - **典型应用**:向容器或流中写入数据。 - **示例**:`ostream_iterator`(用于输出流)。 --- ### 3. **前向迭代器(Forward Iterator)** - **功能**:继承自输入迭代器,支持多次读写和重复遍历。 - **支持的操作**:所有输入迭代器的操作,且可以多次递增。 - **典型容器**:单链表(如 `forward_list`)、哈希表(如 `unordered_set`)。 --- ### 4. **双向迭代器(Bidirectional Iterator)** - **功能**:继承自前向迭代器,支持双向移动(向前和向后)。 - **支持的操作**:新增 `--`(前置/后置递减)。 - **典型容器**:双链表(如 `list`)、关联容器(如 `set`、`map`)。 --- ### 5. **随机访问迭代器(Random Access Iterator)** - **功能**:功能最强,支持直接跳跃访问任意位置。 - **支持的操作**: - 所有双向迭代器的操作。 - `+`/`-`、`+=`/`-=`(跳跃多个位置)。 - `[]`(下标访问)、比较大小(如 `<`, `>`)。 - **典型容器**:连续内存容器(如 `vector`、`deque`、数组)。 --- ### **迭代器关系图示** ``` 输入迭代器 → 前向迭代器 → 双向迭代器 → 随机访问迭代器 输出迭代器(独立分支) ``` --- ### **关键区别** - **随机访问迭代器**效率最高(如 `vector` 的迭代器)。 - **双向迭代器**仅支持逐步移动(如 `list`)。 - 算法需根据迭代器类型选择实现(如 `sort` 需随机访问,`list` 需用自己的 `sort` 方法)。 理解迭代器类型有助于高效使用 STL 容器和算法!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值