C++11 为我们带来了许多极大提升代码可读性与开发效率的新特性,其中之一就是 基于范围的 for 循环(range-based for loop)。它让我们在遍历容器(如数组、std::vector、std::map 等)时,不再需要写复杂的下标或迭代器,大大简化了代码。
1. 为什么需要基于范围的for循环?
在 C++11 之前,遍历一个容器的常用方法是这样:
1 2 3 4
| std::vector<int> nums = {1, 2, 3, 4, 5}; for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) { std::cout << *it << " "; }
|
这种写法虽然功能完整,但冗长且不利于阅读。
而 C++11 引入的 基于范围的 for 循环,让代码变得更简单:
1 2 3
| for (auto n : nums) { std::cout << n << " "; }
|
2.基本语法
1 2 3
| for (declaration : container) { }
|
- declaration:用于接收容器中的每个元素(可以是值、引用、常量引用等)。
- container:任何支持 begin() 和 end() 的容器,例如数组、std::vector、std::list 等。
示例1:简单遍历std::vector
1 2 3 4 5 6 7 8 9 10 11
| #include <iostream> #include <vector>
int main() { std::vector<int> nums = {1, 2, 3, 4, 5};
for (auto n : nums) { std::cout << n << " "; } return 0; }
|
输出:
示例 2:修改容器内容(使用引用)
默认情况下,auto n 是按值复制的,修改 n 不会影响原容器。如果你需要修改容器中的内容,应使用引用:
1 2 3
| for (auto& n : nums) { n *= 2; }
|
或者防止被修改时使用常量引用:
1 2 3
| for (const auto& n : nums) { std::cout << n << " "; }
|
示例 3:遍历原生数组
1 2 3 4
| int arr[] = {1, 2, 3, 4, 5}; for (auto n : arr) { std::cout << n << " "; }
|
示例4:访问次数
基于范围的for循环遍历的对象可以是一个表达式或者容器/数组等。假设我们对一个容器进行遍历,在遍历过程中for循环对这个容器的访问频率是一次还是多次呢?我们通过下面的例子验证一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <vector> using namespace std;
vector<int> v{ 1,2,3,4,5,6 }; vector<int>& getRange() { cout << "get vector range..." << endl; return v; }
int main(void) { for (auto val : getRange()) { cout << val << " "; } cout << endl;
return 0; }
|
输出的结果如下:
1 2
| get vector range... 1 2 3 4 5 6
|
从上面的结果中可以看到,不论基于范围的for循环迭代了多少次,函数getRange()只在第一次迭代之前被调用,得到这个容器对象之后就不会再去重新获取这个对象了。