1. 迭代器模式的核心价值
在C++开发中,我们经常需要处理各种集合数据结构的遍历操作。传统做法是直接暴露容器内部结构,但这会导致代码耦合度高、维护困难。迭代器模式通过提供统一的遍历接口,完美解决了这个痛点。
我曾在处理一个多线程日志分析系统时,面对不同格式的日志文件(内存数组、链表、文件流),迭代器模式让遍历操作变得异常简洁。客户端代码只需知道迭代器接口,完全不需要关心底层是vector还是map,更不用在意数据存储在内存还是磁盘。
2. 模式实现深度解析
2.1 基础架构组成
标准迭代器模式包含三个关键组件:
- 迭代器接口:定义First()、Next()、IsDone()等基本操作
- 具体迭代器:实现特定集合的遍历逻辑
- 集合接口:提供创建迭代器的方法
template <typename T, typename U> class Iterator { public: virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() = 0; virtual T CurrentItem() = 0; };2.2 STL迭代器对比
C++标准库已经内置了迭代器实现,但自定义迭代器在特定场景仍有优势:
- 支持复杂遍历逻辑(如树结构的深度优先/广度优先)
- 可以添加过滤条件(只遍历符合特定条件的元素)
- 实现线程安全的遍历操作
// STL迭代器示例 std::vector<int> vec{1,2,3}; for(auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl; }3. 实战应用案例
3.1 自定义集合迭代
假设我们需要处理一个分块存储的大型数据集:
class ChunkedArray { std::vector<std::vector<int>> chunks; public: class Iterator { ChunkedArray& array; size_t chunkIdx = 0; size_t elemIdx = 0; public: Iterator(ChunkedArray& arr) : array(arr) {} void First() { chunkIdx = elemIdx = 0; } void Next() { if(++elemIdx >= array.chunks[chunkIdx].size()) { chunkIdx++; elemIdx = 0; } } int CurrentItem() { return array.chunks[chunkIdx][elemIdx]; } bool IsDone() { return chunkIdx >= array.chunks.size(); } }; Iterator CreateIterator() { return Iterator(*this); } };3.2 带过滤的迭代器
实现只返回偶数的迭代器:
class EvenIterator { std::vector<int>::iterator current; std::vector<int>::iterator end; public: EvenIterator(std::vector<int>& vec) : current(vec.begin()), end(vec.end()) {} void First() { current = std::find_if(current, end, [](int x){ return x%2 == 0; }); } void Next() { if(current != end) { current = std::find_if(++current, end, [](int x){ return x%2 == 0; }); } } int CurrentItem() { return *current; } bool IsDone() { return current == end; } };4. 高级应用技巧
4.1 线程安全迭代器
在多线程环境下,需要保证迭代过程的原子性:
class ThreadSafeIterator { std::mutex mtx; std::vector<int>::iterator current; //...其他成员 void Next() { std::lock_guard<std::mutex> lock(mtx); ++current; } //...其他方法 };4.2 组合迭代器
处理嵌套数据结构时,可以组合多个迭代器:
class MatrixIterator { using RowIter = std::vector<int>::iterator; std::vector<RowIter> rowIters; size_t currentRow = 0; public: MatrixIterator(std::vector<std::vector<int>>& matrix) { for(auto& row : matrix) { rowIters.push_back(row.begin()); } } //...实现迭代器接口 };5. 性能优化与陷阱
5.1 虚函数开销问题
迭代器接口通常需要定义为虚函数,这会带来一定的性能开销。在性能敏感场景,可以考虑使用CRTP模式:
template <typename Derived> class IteratorBase { public: Derived& derived() { return static_cast<Derived&>(*this); } void First() { derived().FirstImpl(); } void Next() { derived().NextImpl(); } //...其他方法 }; class ConcreteIterator : public IteratorBase<ConcreteIterator> { public: void FirstImpl() { /* 具体实现 */ } void NextImpl() { /* 具体实现 */ } //...其他实现 };5.2 迭代器失效问题
特别注意在遍历过程中修改容器会导致迭代器失效:
std::vector<int> vec{1,2,3}; auto it = vec.begin(); vec.push_back(4); // 使迭代器失效 // 此时使用it是未定义行为6. 现代C++的演进
C++11引入的range-based for循环底层就是使用迭代器:
for(auto& item : container) { // 等价于 // for(auto it=container.begin(); it!=container.end(); ++it) }C++20引入了更强大的ranges库,进一步简化迭代器使用:
#include <ranges> std::vector<int> vec{1,2,3,4,5}; auto even = vec | std::views::filter([](int x){ return x%2 == 0; }); for(auto x : even) { std::cout << x << std::endl; }7. 设计模式组合应用
迭代器常与其他模式配合使用:
- 组合模式:遍历复杂对象结构
- 访问者模式:在遍历过程中执行操作
- 工厂模式:创建不同类型的迭代器
// 组合模式中的迭代器示例 class Component { public: virtual std::unique_ptr<Iterator<Component>> CreateIterator() = 0; //...其他接口 }; class Composite : public Component { std::vector<std::unique_ptr<Component>> children; public: class CompositeIterator : public Iterator<Component> { //...实现遍历逻辑 }; std::unique_ptr<Iterator<Component>> CreateIterator() override { return std::make_unique<CompositeIterator>(*this); } };8. 实际项目经验分享
在开发数据库查询引擎时,我们实现了多种迭代器:
- 顺序扫描迭代器:全表扫描
- 索引扫描迭代器:通过B+树索引定位
- 合并迭代器:归并多个有序结果集
- 物化迭代器:缓存中间结果
关键优化点:
- 减少虚函数调用(使用模板)
- 预取下一批数据(异步IO)
- 批量处理(每次迭代返回多个元素)
// 批处理迭代器示例 template <typename T> class BatchIterator { std::vector<T> buffer; size_t batchSize = 1000; //...其他成员 std::vector<T> NextBatch() { std::vector<T> result; result.reserve(batchSize); for(size_t i=0; i<batchSize && !IsDone(); ++i) { result.push_back(CurrentItem()); Next(); } return result; } };9. 测试与调试技巧
迭代器实现的常见问题:
- 边界条件处理(空容器、最后一个元素)
- 并发修改检测
- 内存泄漏(特别是工厂创建的迭代器)
建议的测试用例:
TEST(IteratorTest, EmptyContainer) { Container<int> empty; auto it = empty.CreateIterator(); EXPECT_TRUE(it->IsDone()); } TEST(IteratorTest, ConcurrentModification) { Container<int> container; auto it = container.CreateIterator(); container.Add(1); // 应该抛出异常或检测到修改 ASSERT_THROW(it->Next(), ConcurrentModificationException); }10. 扩展思考
迭代器模式在现代C++中的新形态:
- 协程迭代器:C++20协程实现异步迭代
- 并行迭代器:STL并行算法背后的迭代器
- 惰性求值迭代器:只在需要时计算下一个元素
// 协程实现的异步迭代器示例 generator<int> async_range(int start, int stop) { for(int i=start; i<stop; ++i) { co_await std::suspend_always{}; co_yield i; } } void consumer() { for co_await (int i : async_range(0, 10)) { std::cout << i << std::endl; } }在实际工程中,迭代器模式的价值不仅在于封装遍历逻辑,更重要的是它提供了一种统一的操作接口,使得算法可以独立于具体的数据结构。这也是STL算法如std::for_each、std::transform等能够通用的关键所在。