相比于c++98的老标准,c++11新标准增加了范围for语句(range for statement)。
范围for语句的语法形式为:
for (declaration:expression)
statement
expression表示的必须是一个序列,比如用花括号括起来的初始值列表,数组,或者vector和string等类型的对象。这些类型共有的一个特点是拥有能返回迭代器的begin()和end()成员。
declaration定义一个变量,序列中的每个元素都得转换成该变量的类型。确保类型相容的最简单办法是使用auto类型说明符,这个关键字可以令编译器帮助我们找到指定合适的类型。如果对元素执行写操作,必须要定义成引用,当然如果对于一个类型来说,元素的复制太昂贵的话,也要定义成引用,以节省运行时间。
每次迭代都会重新定义循环控制变量,并将其初始化为序列中的一个值,之后才会执行statement,所有元素处理完毕后循环终止。
以下面的代码为例,其目的是输出一个vector类型元素的值
vector<int> v1={1,2,3,4,5,6,7,8,9};
for(auto x:v1)
cout<<x<<" ";
cout<<endl;
在这个例子中,v1是一个序列,因为vector有begin()和end()成员,auto x 代表declaration,定义了一个变量,每次执行时都会用v1中的元素来给变量x赋值。当v1中所有元素都输出完之后循环终止,再执行语句cout<<endl
。其实上述的代码等价成如下代码:
vector<int> v1={1,2,3,4,5,6,7,8,9};
for(auto beg=v1.begin(),end=v1.end();beg!=end;++beg)
{
auto x=*beg;
cout<<x<<" ";
}
cout<<endl;
从上面的等价代码中我们可以得出另外一个结论:不能通过范围for循环语句给容器增减元素,因为在范围for循环语句中预存了该序列end()的值,一旦我们给容器增减元素,就可能会导致该序列中end()函数的值发生改变,这就导致范围for循环语句中之前预存的end()函数的值就失效了。
如果我们想要改变序列中元素的值,我们要给变量定义成引用,如下面的代码例子所示:
vector<int> v1={1,2,3,4,5,6,7,8,9};
for(auto& x:v1)
x*=2;
当然如果我们不想改变一个序列中元素的值,但元素的复制太昂贵,这样我们也可以定义成引用,如下面代码例子所示:
//假设vector<string> v1中存储的字符串很长
for(const auto&x: v1)
cout<<x<<" ";
cout<<endl;