语法格式
for(declaration:expression)
statement
其中,expression是可支持迭代器的容器类对象,如vector,string,数组等
基本使用
遍历输出
遍历输出时,范围for中nums对象中取出每一个元素给num,故num表示nums中的每一个元素,其数据类型也就是nums的元素类型
vector<int> nums = { 1,2,3,4,5};
for (int num : nums)
{
num++;
cout << num << " ";
}
cout << endl;
遍历时修改
如果我们想在遍历nums的同时对nums的元素进行修改,只需将num的类型改为左值引用即可
vector<int> nums = { 1,2,3,4,5};
for (int& num : nums)
{
num++;//使用左值引用可修改nums中的元素
cout << num << " ";
}
cout << endl;
遍历时只读
for (const auto& num : nums)
{
num++;//错误,const修饰下的num不能被修改,只可读
cout << num << " ";
}
等价实现
左值引用的范围for等价于以下实现
for (auto iter = nums.begin(); iter != nums.end(); iter++)
{
auto& r = *iter;
r++;
cout << r << endl;
}
注意事项
由上述等价实现可以看到,范围for语句的实现是基于迭代器的,已经预存了end()的值,因此不能在遍历的过程中向序列中添加元素,否则会导致迭代器的失效,如下
for (auto num : nums)
{
nums.push_back(1);//不能在范围for的使用过程中添加元素
cout << num << " ";
}
此外,如下代码是错误的:
因为对于 vector<bool>
类型的容器 nums
,范围 for 语句中的 auto& num
并不是一个左值引用,而是一个右值引用。这是因为vector<bool>
使用了特殊的实现方式来节省空间,将每个 bool
压缩为一个比特位(bit)。在 C++ 标准中,对于 vector<bool>
类型的容器,其迭代器返回的并不是 bool&
类型的引用,而是一个特殊的代理对象,因此无法直接通过迭代器修改容器中的元素值。
以下修改是正确的
1.将左值引用改为右值引用
vector<bool> nums = { true,false,true,false };
for (auto&& num : nums)
{
cout << num << " ";
}
cout << endl;
2.使用普通遍历循环
for (size_t i = 0; i < nums.size(); ++i) {
bnums[i] = true; // 修改元素值
}
3.使用普通的迭代器对象遍历循环
for (auto it = nums.begin(); it != nums.end(); ++it) {
*it = true; // 修改元素值
}