引言
C++11引入了多种新特性,其中基于范围的for循环(Range-based for loop)是一个显著改进,旨在简化容器和数组的遍历操作。这一特性不仅提高了代码的可读性,还减少了迭代器使用的复杂性,并有效避免了越界和迭代器失效等问题。
技术分析
基于范围的for循环的语法结构如下:
for (declaration : expression) {
// 循环体
}
declaration
:遍历声明,在遍历过程中,当前被遍历到的元素会被存储到声明的变量中。expression
:要遍历的对象,它可以是表达式、容器、数组、初始化列表等。
该循环通过对象的迭代器自动处理元素访问,简化了代码并避免了越界问题。它适用于定义了begin
和end
方法的对象,但不适用于new
创建的动态数组或多维数组的外层循环。
基于范围的for循环每次循环都会将序列中的下一个元素赋值给声明的变量,直到循环结束。编译器会自动处理迭代器的初始化、增量及结束等细节,无需手动操作。
使用细节
遍历容器: 基于范围的for循环可以遍历各种容器,如
std::vector
、std::list
、std::array
等。#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}修改容器元素: 若需要在遍历过程中修改元素的值,需要使用引用。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto& num : vec) {
num++;
}
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}只读遍历: 如果只需要读数据而不允许修改元素的值,可以使用
const
定义保存元素数据的变量。#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (const auto& num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}遍历关联型容器: 对于关联型容器如
std::map
和std::set
,基于范围的for循环同样适用。但需要注意的是,对于std::set
,内部元素都是只读的,因此auto&
会被视为const auto&
。对于std::map
,虽然可以得到一个std::pair
引用,但不能修改first
值(即key值)。#include <iostream>
#include <map>
int main() {
std::map<int, std::string> m = {{1, "lucy"}, {2, "lily"}, {3, "tom"}};
for (const auto& item : m) {
std::cout << "id: " << item.first << ", name: " << item.second << std::endl;
}
return 0;
}访问次数: 对一个表达式或者容器/数组等对象进行基于范围的for循环遍历,冒号后边的表达式只会被执行一次。在得到遍历对象之后会先确定好迭代的范围,基于这个范围直接进行遍历。
#include <iostream>
#include <vector>
std::vector<int>& getRange() {
std::cout << "get vector range..." << std::endl;
static std::vector<int> v = {1, 2, 3, 4, 5};
return v;
}
int main() {
for (auto val : getRange()) {
std::cout << val << " ";
}
std::cout << std::endl;
return 0;
}
结论
基于范围的for循环是C++11引入的一个重要特性,它极大地简化了容器和数组的遍历操作,提高了代码的可读性和安全性。通过自动处理迭代器的细节,避免了越界和迭代器失效等问题。然而,在使用时需要注意容器的特性和遍历需求,选择适当的遍历方式。