基于范围的for循环是C++2.0中除了auto关键字外另一个非常实用且简单的小工具,用于实现容器中的数据的遍历,具体形式如下:
/*
*decl:变量的声明
*coll:已定义好的容器
*/
for(decl:coll){
statement
}
使用的方式也很简单:
for(int i:{1,2,3,4,5}){
cout<<i<<endl;
}
上面的例子编译器会形成一个initializer_list,背后关联一个容器array<int,5>,{}中的数据保存在容器array中。编译器从容器中逐一拿出赋值给i,然后在函数体中处理i。
这里需要注意几点:
1、一般我们会使用STL提供的容器vector、deque、map等,而不是上面例子中那么直白的直接临时构建容器。(变量声明的类型一般为auto,即让编译器帮助我们判断容器中的数据类型,因为容器中的数据类型可能书写会比较复杂)
2、变量的声明int i有一定的讲究,如果容器中的数据是基本数据类型int或char,可以直接声明对应类型的变量;如果容器中的数据类型是double、string甚至是更加复杂的数据类型,就建议声明对应类型变量的引用。因为引用在32位编译器中占4个字节,而double类型变量占8个字节,string类型变量我在32位VC编译器测试了一下变态的占用了28个字节,因此对于容器中有大量数据时,使用引用可以大大节省时间和空间的开销。
3、若变量的声明为引用,且已经确定不会修改容器中的元素,请记得在变量声明前边加const修饰,否则容器中的元素可能会被改变。
例子如下:
vector<int> vec{1,2,3,4,5};//使用vector容器
...
for(auto i:vec){//直接声明对应类型,容器中的元素不会改变(只读)
cout<<i<<endl;
}
for(auto& i:vec){//声明对应类型的引用,容器中的元素可以被改变(可读可写)
i*=2;
}
for(const auto& i:vec){//声明对应类型的常量引用,容器中的元素不会被改变(只读)
cout<<i<<endl;
}
基于范围的for循环确实简化了程序员的编程,但需要明确的是,程序员工作的减轻往往也就意味着编译器工作的加重。基于范围的for循环编译器同样在背后帮我们实现了额外的工作。
//编译器遇到形如for(decl:coll){statement}后会自动转化为
for(auto _pos=coll.begin(),_end=coll.end();_pos!=_end;++_pos){//begin()和end()为相应容器对应的函数,获取头尾迭代器
decl=_*pos;
statement;
}
//或者
for(auto _pos=begin(coll),_end=end(coll);_pos!=_end;++_pos)
{//begin()和end()为全局函数,获取对应容器的头尾迭代器
decl=_*pos;
statement;
}