C++ STL迭代器是访问容器元素的通用方式,分为输入、输出、前向、双向和随机访问五种类型,分别适用于不同场景;通过begin()和end()获取迭代器,可遍历vector、list、map等容器;使用时需注意插入或删除导致的迭代器失效问题,尤其在vector中易发生;可通过自定义迭代器类并重载*、++、==等操作符实现灵活访问;迭代器还与算法如copy、transform、find结合使用,提升代码复用性和效率。

C++ STL 迭代器是访问容器中元素的通用方式,它类似于指针,但提供了更高级的功能和安全性。理解迭代器的类型和用法是掌握 STL 的关键。
迭代器类型与用法详解:
迭代器是连接算法和容器的桥梁。它允许我们以统一的方式访问不同类型容器中的元素,而无需关心容器底层的实现细节。
C++ STL 迭代器有哪些类型?
C++ STL 提供了五种主要的迭代器类型,每种类型都具有不同的功能和限制。了解这些类型有助于我们选择最适合特定任务的迭代器。
立即学习“C++免费学习笔记(深入)”;
输入迭代器 (Input Iterator): 只读迭代器,只能单向移动,用于从容器中读取数据。只能读取一次,不能多次读取相同位置的值。例如,
istream_iterator
。输出迭代器 (Output Iterator): 只写迭代器,只能单向移动,用于向容器中写入数据。只能写入一次,不能多次写入相同位置的值。例如,
ostream_iterator
。前向迭代器 (Forward Iterator): 读写迭代器,可以单向移动,可以多次读取和写入相同位置的值。它具有输入迭代器和输出迭代器的所有功能。
双向迭代器 (Bidirectional Iterator): 读写迭代器,可以双向移动,可以多次读取和写入相同位置的值。它具有前向迭代器的所有功能,并增加了向后移动的能力。
list
,set
,multiset
,map
,multimap
等容器通常提供双向迭代器。随机访问迭代器 (Random Access Iterator): 读写迭代器,可以随机访问容器中的任何元素,可以进行加减运算,比较大小等操作。它具有双向迭代器的所有功能,并增加了随机访问的能力。
vector
,deque
,array
等容器通常提供随机访问迭代器。
如何使用迭代器遍历容器?
使用迭代器遍历容器是 STL 中常见的操作。以下是一些示例,展示了如何使用不同类型的迭代器遍历不同类型的容器。
示例 1: 使用迭代器遍历 vector
#include#include int main() { std::vector vec = {1, 2, 3, 4, 5}; // 使用迭代器遍历 vector for (std::vector ::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // 使用 const_iterator 遍历 vector (只读) for (std::vector ::const_iterator it = vec.cbegin(); it != vec.cend(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // 使用 auto 关键字简化迭代器声明 (C++11 及以上) for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // 使用范围 for 循环 (C++11 及以上) for (int element : vec) { std::cout << element << " "; } std::cout << std::endl; return 0; }
示例 2: 使用迭代器遍历 list
#include#include int main() { std::list
lst = {1, 2, 3, 4, 5}; // 使用迭代器遍历 list for (std::list ::iterator it = lst.begin(); it != lst.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; return 0; }
示例 3: 使用迭代器遍历 map
#include#include
迭代器失效是什么?如何避免?
迭代器失效是指迭代器指向的元素不再有效或不存在。这通常发生在容器修改后,例如插入、删除元素等。避免迭代器失效是编写健壮的 STL 代码的关键。
常见导致迭代器失效的操作:
-
vector
和deque
: 插入或删除元素可能导致所有迭代器失效。特别是在vector
中,如果插入操作导致重新分配内存,则所有迭代器都会失效。 -
list
: 插入元素不会导致迭代器失效,删除元素只会使指向被删除元素的迭代器失效。 -
map
和set
: 插入元素不会导致迭代器失效,删除元素只会使指向被删除元素的迭代器失效。
避免迭代器失效的策略:
-
尽量使用返回值: 某些容器操作(例如
erase
)会返回指向下一个有效元素的迭代器。使用这些返回值可以避免迭代器失效。std::vector
vec = {1, 2, 3, 4, 5}; for (auto it = vec.begin(); it != vec.end(); ) { if (*it % 2 == 0) { it = vec.erase(it); // erase 返回指向下一个元素的迭代器 } else { ++it; } } 避免在循环中修改容器大小: 如果需要在循环中修改容器大小,可以考虑使用
list
或map/set
,因为它们在插入和删除元素时对迭代器的影响较小。或者,可以先收集需要删除的元素,然后在循环结束后一次性删除。使用范围 for 循环 (C++11 及以上): 范围 for 循环在某些情况下可以避免迭代器失效的问题,但需要注意,如果在循环体内修改容器大小,仍然可能导致未定义行为。
小心使用
insert
和erase
: 在vector
和deque
中,insert
和erase
操作会移动元素,导致迭代器失效。需要特别小心处理。
理解迭代器失效的原因和避免方法,可以帮助我们编写更可靠和高效的 STL 代码。
如何自定义迭代器?
虽然 STL 提供了丰富的迭代器类型,但在某些情况下,我们可能需要自定义迭代器来满足特定的需求。自定义迭代器需要实现特定的接口和行为。
自定义迭代器的步骤:
定义迭代器类: 创建一个类,用于表示自定义迭代器。
定义迭代器类型别名: 在类中定义一些类型别名,例如
iterator_category
,value_type
,difference_type
,pointer
,reference
。这些类型别名用于指定迭代器的类型和相关信息。实现迭代器操作符: 重载迭代器需要支持的操作符,例如
*
,++
,==
,!=
等。实现
begin()
和end()
方法: 在容器类中实现begin()
和end()
方法,返回自定义迭代器的实例。
示例:自定义一个简单的数组迭代器
#includetemplate class ArrayIterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; using pointer = T*; using reference = T&; ArrayIterator(T* ptr) : m_ptr(ptr) {} reference operator*() const { return *m_ptr; } pointer operator->() const { return m_ptr; } ArrayIterator& operator++() { ++m_ptr; return *this; } ArrayIterator operator++(int) { ArrayIterator temp = *this; ++m_ptr; return temp; } ArrayIterator& operator--() { --m_ptr; return *this; } ArrayIterator operator--(int) { ArrayIterator temp = *this; --m_ptr; return temp; } ArrayIterator operator+(difference_type n) const { return ArrayIterator(m_ptr + n); } ArrayIterator operator-(difference_type n) const { return ArrayIterator(m_ptr - n); } difference_type operator-(const ArrayIterator& other) const { return m_ptr - other.m_ptr; } bool operator==(const ArrayIterator& other) const { return m_ptr == other.m_ptr; } bool operator!=(const ArrayIterator& other) const { return m_ptr != other.m_ptr; } bool operator<(const ArrayIterator& other) const { return m_ptr < other.m_ptr; } bool operator>(const ArrayIterator& other) const { return m_ptr > other.m_ptr; } bool operator<=(const ArrayIterator& other) const { return m_ptr <= other.m_ptr; } bool operator>=(const ArrayIterator& other) const { return m_ptr >= other.m_ptr; } private: T* m_ptr; }; template class MyArray { public: using iterator = ArrayIterator ; MyArray() {} iterator begin() { return iterator(m_data); } iterator end() { return iterator(m_data + N); } T& operator[](size_t index) { return m_data[index]; } const T& operator[](size_t index) const { return m_data[index]; } private: T m_data[N]; }; int main() { MyArray arr; arr[0] = 1; arr[1] = 2; arr[2] = 3; arr[3] = 4; arr[4] = 5; for (auto it = arr.begin(); it != arr.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; return 0; }
这个示例展示了如何自定义一个简单的数组迭代器,并将其用于遍历自定义的数组类。自定义迭代器可以让我们更灵活地控制数据的访问方式,并与其他 STL 算法进行集成。
如何使用迭代器进行算法操作?
STL 算法通常使用迭代器作为输入,对容器中的元素进行操作。理解如何使用迭代器进行算法操作是掌握 STL 的关键。
示例:使用 std::copy
算法复制容器中的元素
#include#include #include int main() { std::vector source = {1, 2, 3, 4, 5}; std::vector destination(source.size()); // 使用 std::copy 算法复制 source 到 destination std::copy(source.begin(), source.end(), destination.begin()); // 打印 destination 中的元素 for (int element : destination) { std::cout << element << " "; } std::cout << std::endl; return 0; }
示例:使用 std::transform
算法转换容器中的元素
#include#include #include #include int main() { std::vector source = {1, 2, 3, 4, 5}; std::vector destination(source.size()); // 使用 std::transform 算法将 source 中的元素乘以 2 并存储到 destination std::transform(source.begin(), source.end(), destination.begin(), [](int x) { return x * 2; }); // 打印 destination 中的元素 for (int element : destination) { std::cout << element << " "; } std::cout << std::endl; return 0; }
示例:使用 std::find
算法查找容器中的元素
#include#include #include int main() { std::vector vec = {1, 2, 3, 4, 5}; // 使用 std::find 算法查找元素 3 auto it = std::find(vec.begin(), vec.end(), 3); if (it != vec.end()) { std::cout << "Found element: " << *it << std::endl; } else { std::cout << "Element not found" << std::endl; } return 0; }
这些示例展示了如何使用迭代器与 STL 算法结合,对容器中的元素进行各种操作。掌握这些技巧可以让我们更高效地使用 STL。










