不能直接用 std::vector::iterator 实现迭代器模式,因为该模式要求封装容器内部结构、解耦实现细节,而直接暴露标准库迭代器或原始指针会破坏封装性;必须自定义迭代器类,提供 begin()/end()、operator++、operator*、operator!= 等接口,并确保跨容器比较安全、end() 为哨兵、生命周期可控。

为什么不能直接用 std::vector::iterator 来“实现”迭代器模式
迭代器模式不是指用标准库的迭代器,而是指自己封装一个类,对外提供统一的 begin()/end()、operator++、operator* 等接口,让使用者能用 for (auto& x : container) 或手写 while (it != end) 的方式遍历——关键是「解耦容器内部结构」。直接暴露 std::vector 的原始指针或下标,就违背了模式本意。
常见错误现象:for (int i = 0; i 循环、或把 <code>std::vector<int>::iterator</int> 当作成员变量直接返回——这没封装行为,也没控制访问边界,更谈不上可扩展(比如你想支持反向遍历、跳过空值、懒计算等)。
- 真正要做的,是定义自己的
Iterator类,重载operator!=、operator++、operator*、operator-> - 容器类需提供
begin()和end()成员函数,返回该Iterator类型 -
Iterator通常需是容器的嵌套类(或友元),才能访问私有数据(如底层数组、size、当前索引)
如何写一个只读的随机访问迭代器(以 int 数组容器为例)
假设你有个简单容器 IntContainer,内部用 std::vector<int></int> 存储数据。你需要它支持范围 for 和手动迭代。重点不是功能多强大,而是接口契约清晰、行为可预测。
关键点在于:迭代器必须能比较相等性、能递进、能解引用;且 end() 迭代器不指向有效元素,仅作哨兵。
立即学习“C++免费学习笔记(深入)”;
-
operator!=必须实现(范围 for 底层用!=判断终止),不能只靠==取反 -
operator++推荐返回Iterator&(前缀),方便链式调用;后缀版若不用可不写 -
operator*返回const T&(只读场景),避免意外修改底层数据 - 迭代器类需声明为
public,且容器的begin()/end()返回值类型必须严格匹配
class IntContainer {
std::vector<int> data_;
public:
class Iterator {
const std::vector<int>* container_;
size_t index_;
public:
Iterator(const std::vector<int>* c, size_t i) : container_(c), index_(i) {}
int operator*() const { return (*container_)[index_]; }
Iterator& operator++() { ++index_; return *this; }
bool operator!=(const Iterator& other) const {
return index_ != other.index_ || container_ != other.container_;
}
};
<pre class="brush:php;toolbar:false;">Iterator begin() { return Iterator(&data_, 0); }
Iterator end() { return Iterator(&data_, data_.size()); }};
为什么 operator!= 要同时比较 container_ 和 index_
因为两个迭代器可能来自不同容器实例。如果只比 index_,那么 containerA.begin() != containerB.end() 可能误判为 false(比如两者 index_ 都是 0),导致循环提前退出或无限执行。C++ 标准库迭代器也要求跨容器比较结果为 true(除非是同一个容器的合法迭代器对)。
另一个易忽略点:end() 迭代器的 index_ 是 size(),不是 size()-1。解引用 end() 是未定义行为,所以 operator* 不应被调用——但你的实现里最好加断言或注释提醒,而不是静默返回垃圾值。
- 不要在
operator*里做边界检查(性能敏感),但可在调试版用assert(index_ size()) - 如果容器支持修改(如插入/删除),迭代器可能失效;此时应明确文档说明“迭代器不保证强异常安全”,或按需实现失效检测(较复杂,初学可暂不处理)
- 若想支持
const容器,还需补充const_iterator类型,或用模板参数区分(但简单场景用typedef const Iterator const_iterator不够严谨,因operator*返回类型不同)
什么时候该用模板泛化,而不是硬写 int
一旦你发现 IntContainer 里的 int 出现超过两次(比如 std::vector<int></int>、operator* 返回 int、构造参数),就该抽成模板。否则换种类型就得复制粘贴改一遍,违背复用原则。
模板化后,Iterator 需依赖外部传入的 T,且要处理 const 与非 const 版本的差异。最简做法是让 Iterator 带两个模板参数:Container 和 IsConst,再用 std::conditional_t 控制引用类型——但对简单实现,先写一个 template<typename t></typename> 版本已足够清晰。
- 容器类声明写成
template<typename t> class Container { ... };</typename> -
Iterator放在类内,用using value_type = T;并让operator*返回value_type&或const value_type& - 别急着支持
std::iterator_traits——除非你要对接 STL 算法(如std::sort),否则纯手工遍历不需要
最难缠的其实是生命周期管理:确保 Iterator 持有的容器指针始终有效。如果容器被移动或析构,迭代器就成了悬垂指针。简单项目里靠文档约束;工业级实现会考虑用句柄或引用计数,但那已超出“简单迭代器模式”的范畴。


















