C++11未提供foreach关键字,但引入基于范围的for循环;语法为for (auto& x : container),推荐const auto&避免拷贝,容器需支持begin()/end(),且不可在循环中增删元素。

C++11 没有 foreach 关键字,但提供了基于范围的 for 循环(range-based for),语法简洁、语义清晰,且在绝大多数场景下效率不输传统 for。
基本写法:用 for (auto& x : container) 遍历容器
这是最常用、最安全的写法。注意三点:
-
auto&表示引用,避免拷贝;若只读,推荐const auto& - 容器必须支持
begin()和end()(标准容器、C 风格数组、std::initializer_list都满足) - 不能在循环中增删元素(会令迭代器失效,行为未定义)
示例:
std::vectorv = {1, 2, 3}; for (const auto& x : v) { std::cout << x << " "; // 输出:1 2 3 }
什么时候该用 auto、auto& 还是 auto&&?
类型推导直接影响性能和正确性:
立即学习“C++免费学习笔记(深入)”;
-
auto x→ 值拷贝:对std::string、std::vector等重型对象开销明显 -
auto& x→ 左值引用:可读可写,适用于需修改原元素的场景 -
const auto& x→ 只读引用:零拷贝、最常用,尤其遍历只读容器时 -
auto&& x→ 万能引用:能绑定左值/右值,适合泛型代码或接收临时对象,但日常遍历中不必要
别写 for (auto x : v) 遍历 std::string —— 每次都触发深拷贝。
效率对比:和传统 for (size_t i = 0; i 一样快吗?
在开启优化(-O2)时,现代编译器(GCC/Clang/MSVC)对两者生成的汇编几乎完全一致,前提是:
- 容器是标准类型(如
std::vector、std::array) - 没有在循环体内取地址或做复杂别名分析干扰
- 没禁用
operator[]内联或size()缓存(如自定义容器未将size()声明为noexcept且constexpr,可能影响优化)
例外:C 风格数组 int a[10],for (auto& x : a) 直接展开为下标访问,无函数调用开销;而手写 for (int i = 0; i 也很快,但需手动维护长度。
常见陷阱:这些地方一写就崩
实际编码中最容易翻车的几个点:
- 对空容器使用
for (auto& x : *ptr),而ptr为nullptr→ 解引用崩溃,begin()/end()不做空指针检查 - 把
std::map::iterator当成值来遍历:for (auto p : my_map)得到的是std::pair,不是iterator;想用迭代器就得用传统for - 在循环中调用
push_back()或erase()→ 迭代器失效,UB;必须改用索引或erase-remove惯用法 - 用在非标准类型上却没提供
begin()/end()→ 编译失败;可通过 ADL 或定义自由函数补全
真正难处理的从来不是语法,而是「什么时候不该用它」——尤其是涉及生命周期、所有权转移或容器结构变更时,range-based for 会悄悄掩盖问题。









