自定义类支持range-based for需提供begin()和end()函数,返回同一类型迭代器,该迭代器只需支持operator*、operator++、operator!=(或operator==),可为裸指针或自定义struct,且须注意const正确性及避免悬垂引用。

自定义类要支持 range-based for,必须提供 begin() 和 end()
编译器对 for (auto& x : obj) 的展开,本质是查找 obj.begin() 和 obj.end()(优先成员函数,失败则查 ADL 可见的非成员函数)。只要这两个函数存在、返回同一类型迭代器,并且该迭代器支持 operator*、operator++、operator!=(或 operator==),就能用。
不需要继承任何基类,也不需要实现完整的 STL 迭代器概念——range-based for 只用到这三个操作。
-
begin()和end()必须返回可比较、可递增、可解引用的对象 - 迭代器类型可以是裸指针(比如封装 C 风格数组时),也可以是自定义 struct
- 若想同时支持
const对象遍历,还需提供const版本的begin()/end()(成员函数加const限定符,或重载非成员函数)
begin() 和 end() 放哪?成员函数还是非成员函数?
优先用成员函数:简单、直观、不污染命名空间。例如:
class MyContainer {
int data_[5] = {1,2,3,4,5};
public:
int* begin() { return data_; }
int* end() { return data_ + 5; }
const int* begin() const { return data_; }
const int* end() const { return data_ + 5; }
};
若不能改类定义(比如封装第三方结构体),就用非成员函数 + ADL:
struct CArray { int arr[3]; };
auto begin(CArray& c) { return c.arr; }
auto end(CArray& c) { return c.arr + 3; }
auto begin(const CArray& c) { return c.arr; }
auto end(const CArray& c) { return c.arr + 3; }
注意:非成员版本必须和类在同一个命名空间,或通过 ADL 能被找到(比如定义在 CArray 所在命名空间内),否则编译器找不到。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
迭代器只需最小接口,别写多余东西
写一个完整迭代器类时,别一上来就继承 std::iterator 或实现全套 operator--、operator+——range-based for 根本不用它们。
最简可行迭代器示例:
struct MyIter {
int* ptr;
int& operator*() { return *ptr; }
MyIter& operator++() { ++ptr; return *this; }
bool operator!=(const MyIter& other) const { return ptr != other.ptr; }
};
然后让 begin()/end() 返回这个类型即可。如果只用于只读遍历,operator* 返回 const int& 更安全。
- 返回值类型不必和容器元素类型一致,只要能隐式转换成
declaration中声明的类型就行 - 避免在
begin()/end()中做耗时计算;它们可能被多次调用(比如循环体里用了break)
常见错误:空容器、临时对象、const 限定不匹配
这些会导致编译失败或未定义行为:
-
for (auto& x : get_temporary_container())—— 若begin()返回局部指针或引用,循环体中访问就是悬垂行为 - 只提供了非
const成员begin()/end(),但对const MyContainer& c使用范围 for —— 编译失败 -
end()返回的迭代器无法和begin()返回的类型比较(比如一个返回int*,另一个返回MyIter) - 迭代器缺少
operator!=,只写了operator==—— 编译器不会自动取反,会报错
最容易被忽略的是 const 正确性:哪怕你只打算读,也建议一开始就补全 const 版本的 begin()/end(),否则一旦把对象绑到 const 引用,整个循环就废了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










