1、范围-for 循环介绍
for ( declaration : container) {
…… // 每次迭代获得一个元素
}
用最简洁的写法遍历 任何 支持 begin()
/ end()
迭代的容器(std::vector
、std::list
、数组、std::map
…)。
编译器在幕后生成迭代器循环。
1.1、declaration
常见写法
写法 | 意义 | 何时用 |
---|---|---|
auto elem | 按值 拷贝元素 | 元素很小、可忽略拷贝成本 |
auto& elem | 按引用 访问 | 避免拷贝,且可修改原元素 |
const auto& elem | 按常量引用 访问 | 避免拷贝,但保证只读 |
auto
让编译器推断元素的准确类型;&
决定是否按引用。
1.2、典型优势
- 简洁:不用手写迭代器。
- 安全:不会越界,类型自动推断,容器元素类型变动不连锁修改。
- 统一:同一语法可遍历 STL 容器、自定义容器、原生数组。
2、示例:for (auto& task : tasks)
std::list<std::function<void()>> tasks = std::move(main_tasks_);
...
for (auto& task : tasks) {
task(); // 调用每个函数对象
}
片段 | 解析 |
---|---|
tasks | std::list<std::function<void()>> ,元素类型是 std::function<void()> 。 |
auto& task | 引用绑定到当前元素 —— 避免复制 std::function (复制成本高)。编译器推断 task 的实际类型为 std::function<void()>& 。 |
task() | 调用 std::function ,执行排队的回调任务。 |
此循环相当于以下“手动迭代器”写法,但更短、更直观:
for (auto it = tasks.begin(); it != tasks.end(); ++it) {
(*it)();
}
小抄:写 range-for
时该想什么?
-
我要遍历的容器/序列是谁?
container
-
我是否需要修改元素?拷贝代价大吗?
- 拷贝便宜 ➜
auto elem
- 想修改 / 拷贝贵 ➜
auto& elem
- 只读且拷贝贵 ➜
const auto& elem
- 拷贝便宜 ➜
-
然后直接用
elem
做事,无需关心迭代器细节。
掌握这三个步骤,遇到任何 for (auto& x : y)
都能快速读懂并正确编写。