当前位置:网站首页>(P25-P26)基于非范围的for循环、基于范围的for循环需要注意的3个细节
(P25-P26)基于非范围的for循环、基于范围的for循环需要注意的3个细节
2022-06-12 08:01:00 【喜欢打篮球的普通人】
1. for 循环新语法
在介绍新语法之前,先来看一个使用迭代器遍历容器的例子:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> t{
1,2,3,4,5,6 };
for (auto it = t.begin(); it != t.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
- 我们在遍历的过程中需要给出容器的两端:开头(begin)和结尾(end),因为这种遍历方式不是基于范围来设计的。
在基于范围的for循环中,不需要再传递容器的两端,循环会自动以容器为范围展开,并且循环中也屏蔽掉了迭代器的遍历细节,直接抽取容器中的元素进行运算,使用这种方式进行循环遍历会让编码和维护变得更加简便。
- C++98/03 中普通的 for 循环,语法格式:
for(表达式 1; 表达式 2; 表达式 3)
{
// 循环体
}
- C++11 基于范围的 for 循环,语法格式:
for (declaration : expression)
{
// 循环体
}
在上面的语法格式中 declaration 表示遍历声明,在遍历过程中,当前被遍历到的元素会被存储到声明的变量中。
expression 是要遍历的对象,它可以是表达式、容器、数组、初始化列表等。
- 使用基于范围的 for 循环遍历容器,示例代码如下:
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
vector<int> t{
1,2,3,4,5,6 };
for (auto value : t)
{
cout << value << " ";
}
cout << endl;
return 0;
}
在上面的例子中,是将容器中遍历的当前元素拷贝到了声明的变量 value 中,因此无法对容器中的元素进行写操作,如果需要在遍历过程中修改元素的值,需要使用引用。
eg:对容器的遍历过程中,如果只是读数据,不允许修改元素的值,可以使用 const 定义保存元素数据的变量,在定义的时候建议使用 const auto &,这样相对于 const auto 效率要更高一些。
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
vector<int> t{
1,2,3,4,5,6 };
cout << "遍历修改之前的容器: ";
for (auto &value : t)
{
cout << value++ << " ";
}
cout << endl << "遍历修改之后的容器: ";
for (auto &value : t)
{
cout << value << " ";
}
cout << endl;
return 0;
}
- 测试:

- eg:const auto&
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
vector<int> t{
1,2,3,4,5,6 };
for (const auto& value : t)
{
cout << value << " ";
}
return 0;
}
2.使用细节:关系型容器
使用基于范围的 for 循环有一些需要注意的细节,先来看一下对关系型容器 map 的遍历:
- eg:
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main(void)
{
map<int, string> m{
{
1, "lucy"},{
2, "lily"},{
3, "tom"}
};
// 基于范围的for循环方式
for (auto& it : m)
{
cout << "id: " << it.first << ", name: " << it.second << endl;
}
// 普通的for循环方式
for (auto it = m.begin(); it != m.end(); ++it)
{
cout << "id: " << it->first << ", name: " << it->second << endl;
}
return 0;
}
在上面的例子中使用两种方式对 map 进行了遍历,通过对比有两点需要注意的事项:
- 使用普通的 for 循环方式(基于迭代器)遍历关联性容器, auto 自动推导出的是一个迭代器类型,需要使用迭代器的方式取出元素中的键值对(和指针的操作方法相同):
it->first
it->second
- 使用基于范围的 for 循环遍历关联性容器,auto 自动推导出的类型是容器中的 value_type,相当于一个对组(std::pair)对象,提取键值对的方式如下:
it.first
it.second
3.使用细节:元素只读
通过对基于范围的 for 循环语法的介绍可以得知,在 for 循环内部声明一个变量的引用就可以修改遍历的表达式中的元素的值,但是这并不适用于所有的情况
- 对应 set 容器来说,内部元素都是只读的,这是由容器的特性决定的,因此在 for 循环中 auto & 会被视为 const auto & 。
#include <iostream>
#include <set>
using namespace std;
int main(void)
{
set<int> st{
1,2,3,4,5,6 };
for (auto &item : st)
{
cout << item++ << endl; // error, 不能给常量赋值
}
return 0;
}
- 除此之外,在遍历关联型容器时也会出现同样的问题,基于范围的for循环中,虽然可以得到一个std::pair引用,但是我们是不能修改里边的first值的,也就是key值。
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main(void)
{
map<int, string> m{
{
1, "lucy"},{
2, "lily"},{
3, "tom"}
};
for (auto& item : m)
{
// item.first 是一个常量
cout << "id: " << item.first++ << ", name: " << item.second << endl; // error
}
return 0;
}
- 测试:

4.使用细节:访问次数
基于范围的 for 循环遍历的对象可以是一个表达式或者容器 / 数组等。
- 假设我们对一个容器进行遍历,在遍历过程中 for 循环对这个容器的访问频率是一次还是多次呢?
- eg:
#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;
}
- 测试:

- 说明:
从上面的结果中可以看到,不论基于范围的 for 循环迭代了多少次,函数 getRange () 只在第一次迭代之前被调用,得到这个容器对象之后就不会再去重新获取这个对象了。
所以在基于范围的for循环中,若尝试去修改容器中元素的个数,会出现问题。而普通的for循环则不会出现该问题。
原因是:对应基于范围的 for 循环来说,冒号后边的表达式只会被执行一次。在得到遍历对象之后会先确定好迭代的范围,基于这个范围直接进行遍历。如果是普通的 for 循环,在每次迭代的时候都需要判断是否已经到了结束边界。
- eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Test
{
public:
Test(std::initializer_list<string> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
cout << *it << " ";
m_names.push_back(*it);
}
cout << endl;
}
private:
vector<string> m_names;
};
int main(void)
{
Test t({
"jack", "lucy", "tom" });
Test t1({
"hello", "world", "nihao", "shijie" });
std::vector<int> m_numVec = {
1,2,3,4,5};
for (auto& it : m_numVec)
{
//修改元素的个数
m_numVec.erase(m_numVec.begin(), m_numVec.begin()+4);
cout << it << " " << endl;
}
return 0;
}
测试:

参考:基于范围的 for 循环
边栏推荐
- Ceres optimizer usage (self use)
- The project file contains toolsversion= "14.0". This toolset may be unknown or missing workarounds
- Discrete chapter I
- System service configuration service - detailed version
- Explanation and explanation on the situation that the volume GPU util (GPU utilization) is very low and the memory ueage (memory occupation) is very high during the training of pytoch
- C # hide the keyboard input on the console (the input content is not displayed on the window)
- AJ project: online bank project summary
- Numpy generates row vectors and column vectors (1024 water medal text)
- Topic 1 Single_ Cell_ analysis(1)
- Leetcode notes: Weekly contest 275
猜你喜欢

从AC5到AC6转型之路(1)——补救和准备

Alibaba cloud deploys VMware and reports an error

Vision Transformer | Arxiv 2205 - LiTv2: Fast Vision Transformers with HiLo Attention

记录谷粒商城踩坑(一)

Group planning chapter I
![FPGA based communication system receiver [packet detection] development document](/img/50/0d15abc41c6e373b00fa05e299566a.jpg)
FPGA based communication system receiver [packet detection] development document

电脑连接上WiFi但是上不了网

Vision Transformer | CVPR 2022 - Vision Transformer with Deformable Attention

Discrete chapter I

Search and rescue strategy of underwater robot (FISH)
随机推荐
Ten important properties of determinant
Literature reading: raise a child in large language model: rewards effective and generalizable fine tuning
Transformation from AC5 to AC6 (1) - remedy and preparation
The R language converts the data of the specified data column in the dataframe data from decimal to percentage representation, and the data to percentage
Principes et exemples de tâches OpenMP
2.1 linked list - remove linked list elements (leetcode 203)
Record the treading pit of grain Mall (I)
EasyExcel导出Excel表格到浏览器,并通过Postman测试导出Excel【入门案例】
Compiling principle on computer -- function drawing language (II): lexical analyzer
Topic 1 Single_Cell_analysis(2)
(P40-P41)move资源的转移、forward完美转发
qt. qpa. plugin: Could not load the Qt platform plugin “xcb“ in “***“
Cookies and sessions
Understanding and analysis of state estimation and Kalman filter
R language uses neuralnet package to build neural network regression model (feedforward neural network regression model) and calculate MSE value (mean square error) of the model on the test set
20220525 RCNN--->Faster RCNN
Uni app screenshot with canvas and share friends
Compiling principle on computer -- functional drawing language (IV): semantic analyzer
Some summaries of mathematical modeling competition in 2022
CONDA reports an error when creating a virtual environment, and the problem is solved