1 什么是迭代器?
迭代器(Iterator)是C++ STL(标准模板库)中的一种对象,类似于指针,用于遍历容器(如vector、list、map等)中的元素。迭代器将容器的内部数据结构与访问方式解耦,使我们能以统一的方式访问不同容器的元素。
1.1 迭代器的原理
STL迭代器本质上是一种泛型指针,它通过重载运算符(如*、++、--等),让用户能够像操作指针一样操作容器中的元素。每种容器会根据自身的数据结构实现适合自己的迭代器类型。
1.2 迭代器的基本操作
解引用:
*it,访问迭代器指向的元素。前进:
++it,移动到下一个元素。后退:
--it,移动到前一个元素(仅双向及随机访问迭代器支持)。比较:
it1 == it2,判断是否指向同一元素。
2 STL迭代器分类
2.1 输入迭代器(Input Iterator)
特点:
只读访问,每个元素只能访问一次。
支持
++、*操作。常用于数据流输入、只读遍历。
代码示例
#include <iostream>
#include <vector>
// 输入迭代器只读遍历vector
void PrintVectorInputIterator(const std::vector<int>& vec) {
// 使用const_iterator保证只读
std::vector<int>::const_iterator it = vec.begin();
for (; it != vec.end(); ++it) {
std::cout << *it << " "; // 只能读取,不能修改
}
std::cout << std::endl;
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
PrintVectorInputIterator(numbers);
return 0;
}
输入迭代器适合数据读取场景,如处理输入流、只读容器遍历。不能进行元素修改,也不支持多次读取同一元素。
2.2 输出迭代器(Output Iterator)
特点:
只写访问,每个元素只能写一次。
支持
++、*操作。常用于数据流输出、写入算法。
代码示例
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
// 输出迭代器写入vector
void FillVectorOutputIterator(std::vector<int>& vec) {
// 使用std::fill_n和输出迭代器
std::fill_n(vec.begin(), vec.size(), 9); // 将所有元素赋值为9
}
int main() {
std::vector<int> numbers(5);
FillVectorOutputIterator(numbers);
// 使用输出迭代器打印结果
std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
输出迭代器适合写入场景,如输出流、赋值、填充等。不能读取元素值。
2.3 前向迭代器(Forward Iterator)
特点:
可读可写,支持单向多次遍历。
支持
++、*操作。常用于单向链表。
代码示例
#include <forward_list>
#include <iostream>
// 前向迭代器遍历forward_list
void ForwardListExample() {
std::forward_list<int> flist = {10, 20, 30, 40};
std::forward_list<int>::iterator it = flist.begin();
for (; it != flist.end(); ++it) {
std::cout << *it << " ";
*it += 1; // 支持修改
}
std::cout << std::endl;
// 再次遍历
for (auto val : flist) {
std::cout << val << " ";
}
std::cout << std::endl;
}
int main() {
ForwardListExample();
return 0;
}
前向迭代器适合单向链表等场景,可多次遍历,支持读写操作,但不支持反向移动。
2.4 双向迭代器(Bidirectional Iterator)
特点:
可读可写,支持
++和--双向遍历。常用于双向链表、集合等。
代码示例
#include <list>
#include <iostream>
// 双向迭代器正反向遍历list
void ListBidirectionalIteratorExample() {
std::list<int> lst = {5, 10, 15, 20};
// 正向遍历
std::list<int>::iterator it = lst.begin();
for (; it != lst.end(); ++it) {
std::cout << *it << " ";
*it *= 2; // 支持修改
}
std::cout << std::endl;
// 反向遍历
std::list<int>::reverse_iterator rit = lst.rbegin();
for (; rit != lst.rend(); ++rit) {
std::cout << *rit << " ";
}
std::cout << std::endl;
}
int main() {
ListBidirectionalIteratorExample();
return 0;
}
双向迭代器支持前后移动,适合需要反向遍历的场景,如list、set、map等。
2.5 随机访问迭代器(Random Access Iterator)
特点:
可读可写,支持所有指针算术操作(
+、-、[]、比较等)。常用于数组、vector、deque等。
代码示例
#include <vector>
#include <iostream>
// 随机访问迭代器遍历vector
void VectorRandomAccessIteratorExample() {
std::vector<int> vec = {7, 14, 21, 28, 35};
// 随机访问
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " ";
vec[i] += 1; // 支持修改
}
std::cout << std::endl;
// 使用迭代器算术
std::vector<int>::iterator it = vec.begin();
it += 2; // 移动到第三个元素
std::cout << "Third element: " << *it << std::endl;
// 反向遍历
for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {
std::cout << *rit << " ";
}
std::cout << std::endl;
}
int main() {
VectorRandomAccessIteratorExample();
return 0;
}
随机访问迭代器支持高效的索引访问和算术操作,是性能最优的迭代器类型,适合数组、vector等场景。
3 迭代器与其他遍历方式对比
说明
迭代器方式最为通用和安全,推荐优先使用。
范围for循环底层也是通过迭代器实现,适合简单遍历场景。
下标和指针遍历仅适用于支持随机访问的容器,易出错。
4 迭代器的高级用法
4.1 const_iterator
只读迭代器,保证元素不被修改。
#include <vector>
#include <iostream>
// 使用const_iterator只读遍历vector
void PrintConstIterator(const std::vector<int>& vec) {
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " "; // 不能修改*it
}
std::cout << std::endl;
}
4.2 reverse_iterator
反向迭代器,逆序遍历容器。
#include <vector>
#include <iostream>
// 使用reverse_iterator逆序遍历vector
void PrintReverseIterator(const std::vector<int>& vec) {
for (std::vector<int>::const_reverse_iterator rit = vec.rbegin(); rit != vec.rend(); ++rit) {
std::cout << *rit << " ";
}
std::cout << std::endl;
}
4.3 iterator_traits
萃取迭代器类型信息,用于模板泛型编程。
#include <iterator>
#include <vector>
#include <type_traits>
#include <iostream>
// 泛型函数:判断迭代器是否为随机访问类型
template <typename Iterator>
void CheckRandomAccess(Iterator it) {
if (std::is_same<
typename std::iterator_traits<Iterator>::iterator_category,
std::random_access_iterator_tag>::value) {
std::cout << "Random access iterator detected." << std::endl;
} else {
std::cout << "Not a random access iterator." << std::endl;
}
}
int main() {
std::vector<int> v{1,2,3};
CheckRandomAccess(v.begin());
return 0;
}
4.4 std::advance和std::distance
通用迭代器操作,支持不同类型迭代器。
#include <vector>
#include <iostream>
#include <iterator>
// advance和distance示例
void IteratorAdvanceDistanceExample() {
std::vector<int> vec = {10, 20, 30, 40, 50};
auto it = vec.begin();
std::advance(it, 3); // 移动到第4个元素
std::cout << "Fourth element: " << *it << std::endl;
auto dist = std::distance(vec.begin(), it);
std::cout << "Distance from begin to it: " << dist << std::endl;
}
int main() {
IteratorAdvanceDistanceExample();
return 0;
}
5 适用场景
输入迭代器:只读遍历、输入流、算法输入端。
输出迭代器:只写遍历、输出流、算法输出端。
前向迭代器:单向链表、多次遍历、读写操作。
双向迭代器:双向链表、集合、需要反向遍历的场景。
随机访问迭代器:数组、vector、高效索引、算术操作。
6.实践建议
推荐优先使用迭代器和范围for循环遍历容器,保证代码的通用性和安全性。
根据容器类型选择合适的迭代器,提升性能。
结合STL算法和迭代器,简化代码逻辑,提升开发效率。
使用
const_iterator和reverse_iterator等扩展迭代器,满足不同需求。
评论区