auto和iterator是两个不同的概念,但经常结合使用来简化代码
auto用于自动推导变量的类型,本质上是一个关键字,使用auto的时候,编译器会根据变量的初始化表达式来判断变量的类型,就省略了显示声明的步骤。会在编译期进行类型推导,是一种静态类型,编译器在编译时就会确定变量的类型
iterator(迭代器)用于遍历容器的对象,它会为访问容器的元素提供了一种统一的接口,使得无论是数组、链表还是其他容器,都可以通过类似的方式进行访问。还可以通过迭代器来进行前进后退的操作。
主要为什么把它们放在一起进行说明呢,因为我们在使用迭代器的其实大多数时候没有进行声明。因为C++11引入了自动类型推导(auto)的特性。
【也就是在这里,这两者有了联系】
在遍历容器时,使用 auto 关键字可以让编译器根据迭代器的类型自动确定变量的类型,减少了代码的冗余,也可以确保在使用时明确迭代器的有效范围。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> myVector = { 1, 2, 66, 3, 789, 5 };
// 使用 iterator 和 auto 结合
//这里的it就是iterator,只不过用auto进行了说明,编译器会自行识别的
for (auto it = myVector.begin(); it != myVector.end(); ++it)
{
cout << *it << " ";
}
cout << std::endl;
return 0;
}
在上面的例子里面,我们可以看到auto it.......,auto 被用来自动推导myVector.begin()返回的迭代器的类型,无需显式写出类型信息。我们已经知道了auto的作用,但这个it其实就是一个常用的命名约定,表示iterator,在C++里面it会是一个指向容器元素的指针,it在这里也就是我们的iterator了。
iterator(迭代器)
iterator(迭代器的类型可以是输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器,这些类型的迭代器提供了不同程度的功能和灵活性。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// 创建一个 vector
vector<int> myVector = { 1, 2, 3, 4, 5 };
// 使用 begin() 和 end() 迭代器遍历 vector
cout << "Using begin() and end(): ";
for (vector<int>::iterator it = myVector.begin(); it != myVector.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
// 使用 rbegin() 和 rend() 迭代器逆序遍历 vector
cout << "Using rbegin() and rend(): ";
for ( vector<int>::reverse_iterator rit = myVector.rbegin(); rit != myVector.rend(); ++rit)
{
cout << *rit << " ";
}
cout << endl;
// 使用 cbegin() 和 cend() 迭代器遍历 vector,不允许修改元素
cout << "Using cbegin() and cend(): ";
for ( vector<int>::const_iterator cit = myVector.cbegin(); cit != myVector.cend(); ++cit)
{
cout << *cit << " ";
}
cout << endl;
// 使用 crbegin() 和 crend() 迭代器逆序遍历 vector,不允许修改元素
cout << "Using crbegin() and crend(): ";
for ( vector<int>::const_reverse_iterator crit = myVector.crbegin(); crit != myVector.crend(); ++crit)
{
cout << *crit << " ";
}
cout << endl;
return 0;
}
在里面有很多迭代器函数,像最普通的就是begin和end,begin()就是指向容器第一个元素的迭代器 ,你可能会猜到 end()是指向容器最后一个元素的迭代器, 但事实并非如此,实际上,end()是指向容器最后一个元素的下一个位置的迭代器
带上c就代表只读,不可修改,如果有r就代表逆向读取
他们之间有一些通用的功能:
- 比较两个迭代器是否相等(==、!=)。
- 前置和后置递增运算(++)。
- 读取元素的解引用运算符(*)。只能读元素,也就是解引用只能出现在赋值运算符的右边。
- 箭头运算符(->),解引用迭代器,并提取对象的成员
// 使用 auto 进行迭代
for (auto it = myVector.begin(); it != myVector.end(); ++it) {
cout << *it << " ";
}
可以看到上面的代码中的for语句很长,所以在这里auto就可以发挥作用了,自动识别
auto
原理就是根据后面的值,来自己推测前面的类型是什么。auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。这个在迭代器中得到了很好的运用
注意:
1.用auto声明的变量必须初始化(auto是根据后面的值来推测这个变量的类型,如果后面没有值,自然会报错)
2.函数和模板参数不能被声明为auto(原因同上)
3.因为auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid
4.定义在一个auto序列的变量必须始终推导成同一类型
auto还可以在for语句中被运用
int main(){
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for(auto i : v){
cout<<i<<" ";
}
cout<<endl;
return 0;
}
这里for语句中的判断条件就只有 auto i :v ,格式是for(auto i : v)
这是一种简化遍历容器元素的语法,被称为范围(range-based)for 循环。
具体含义是:对于容器 v
中的每个元素,将其值赋给变量 i
,然后执行循环体。在这个例子中,i
会依次取到 1
、2
、3
,并将它们输出到标准输出流 cout
中,每个数字后面加一个空格。
这种语法简化了遍历容器的代码,尤其适用于不需要知道元素索引的情况。对于 vector
这样的顺序容器,范围 for 循环是一种常见的使用方式,使得代码更加简洁易读。
参考文章: