📘 C++ 范围 for
循环详解(Range-based for loop)
一、什么是范围 for
循环?
范围 for
循环(Range-based for loop) 是 C++11 引入的一种简化容器/数组遍历的方式。它通过自动调用容器的 begin()
和 end()
方法,实现对每个元素的遍历,无需手动管理索引或迭代器。
二、语法格式
for (declaration : expression) {
}
declaration
:用于声明当前遍历的元素(可使用 auto
自动推导类型)
expression
:表示要遍历的容器或数组
三、基本原理
✅ 自动调用 begin()
和 end()
范围 for
循环会自动调用容器的 begin()
和 end()
方法,获取起始和结束迭代器,然后依次遍历每个元素。
示例说明:
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
std::cout << num << " ";
}
✅ 等价于传统写法:
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
int num = *it;
std::cout << num << " ";
}
四、适用对象
范围 for
循环适用于以下对象:
类型 |
是否支持 |
示例 |
数组 |
✅ 支持 |
int arr[] = {1, 2, 3}; |
标准库容器 |
✅ 支持 |
std::vector , std::list , std::map |
自定义容器类 |
✅ 支持 |
需要实现 begin() 和 end() 方法 |
字符串(std::string ) |
✅ 支持 |
逐字符遍历 |
原始指针容器 |
❌ 不支持 |
没有 begin() /end() 方法 |
五、优点
优点 |
说明 |
代码简洁 |
避免手动写 begin() /end() |
安全性高 |
不易越界,适合只读遍历 |
可读性强 |
更贴近自然语言,易于理解 |
自动类型推导 |
可使用 auto 自动识别元素类型 |
六、局限性
局限 |
说明 |
不能直接访问索引 |
无法通过循环变量获取当前索引 |
不能反向遍历 |
只能从前往后遍历 |
不能跳过元素 |
无法控制步长(如 i += 2 ) |
不能修改容器结构 |
不能在循环中添加/删除元素 |
七、代码示例
1. 遍历数组
int arr[] = {1, 2, 3, 4, 5};
for (int num : arr) {
std::cout << num << " ";
}
2. 遍历 std::vector
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {10, 20, 30, 40, 50};
for (auto num : nums) {
std::cout << num << " ";
}
return 0;
}
3. 遍历 std::map
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> scores = {
{"Alice", 95},
{"Bob", 80},
{"Charlie", 88}
};
for (const auto &pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
输出:
Alice: 95
Bob: 80
Charlie: 88
4. 遍历 std::string
#include <iostream>
#include <string>
int main() {
std::string str = "Hello";
for (char c : str) {
std::cout << c << " ";
}
return 0;
}
5. 使用引用修改元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
for (auto &num : nums) {
num *= 2;
}
for (auto num : nums) {
std::cout << num << " ";
}
return 0;
}
6. 使用 auto
自动推导类型
#include <iostream>
#include <vector>
int main() {
std::vector<std::string> names = {"Tom", "Jerry", "Spike"};
for (const auto &name : names) {
std::cout << name << std::endl;
}
return 0;
}
八、常见错误与修正
错误写法 |
正确写法 |
说明 |
for (int x : 10) |
for (int x : vector) |
范围 for 必须作用于容器 |
for (int x : {}); |
std::vector<int> v = {1, 2}; for (int x : v) |
空列表不能单独使用 |
for (int &x : const std::vector<int> v) |
for (int x : v) |
不能通过引用修改常量容器 |
for (int x : arr, arr + 5) |
for (int x : arr) |
不需要手动指定范围,自动识别容器边界 |
九、性能与安全建议
建议 |
说明 |
使用 const auto & 遍历只读容器 |
避免拷贝,提高性能 |
使用 auto & 修改容器元素 |
通过引用直接操作原数据 |
避免在循环中修改容器结构 |
如 push_back() 、erase() ,可能导致迭代器失效 |
优先使用 const |
如果不打算修改元素,使用 const auto & 提高代码清晰度 |
十、通俗类比
你可以把范围 for
循环理解为:
for (auto &item : shopping_list) {
std::cout << "Buy: " << item << std::endl;
}
shopping_list
是你要遍历的容器
item
是当前遍历到的元素
- 循环自动帮你“取出”每一个物品,不需要你手动操作索引或指针
十一、术语对照表
英文术语 |
中文解释 |
Range-based for loop |
范围 for 循环 |
Container |
容器(如 vector , map ) |
Iterator |
迭代器(传统 for 循环中使用) |
Reference |
引用(& 表示) |
auto |
自动类型推导 |
const auto & |
常量引用,防止拷贝和修改原始数据 |
十二、设计建议
场景 |
推荐写法 |
只读遍历容器 |
for (const auto &item : container) |
修改容器元素 |
for (auto &item : container) |
遍历字符串 |
for (char c : str) |
遍历 map 的键值对 |
for (const auto &pair : my_map) |
避免拷贝 |
使用引用 & |
避免修改容器结构 |
不在循环中调用 push_back() 、erase() 等方法 |
十三、总结
特性 |
说明 |
语法简洁 |
for (auto &item : container) |
自动调用 begin() / end() |
无需手动写迭代器 |
适用于容器和数组 |
vector , map , array , string 等 |
不能控制索引 |
无法获取当前索引值 |
不适合动态修改容器 |
如增删元素会导致迭代器失效 |