C++11中定义了一种for循环用法,可用于容器的遍历,如下图。
对于一个容器,我们这样写(decl : coll),coll为一个容器,编译器就会把容器中的每个元素依次放入到decl这个变量中,从而完成遍历,且配合auto关键字可自动参数类型推导,很是方便。
但这里关键要注意值和引用含义的区别,当下面elem为值含义时,每次执行都要进行一次赋值的操作,即把vec的一个元素赋值给elem,假如vec这个容器很大,则可想而知每个元素的赋值操作将影响性能。因此,若改为引用含义的elem(即下面的auto&),由于引用本质上是指针,即遍历过程中不需要进行赋值,因此效率上有提升。同时,要注意,如果遍历过程中需要改变vec中的元素值,则必须采用引用(auto&)形式,此时的elem相当于了容器的迭代器,图中elem *=3将vec中每个元素乘上了3。但是,若使用引用时要改变容器中的值时,首先应当考虑该容器内容是否可以直接通过迭代器的方式改变,所有的关联式容器(如set,map)都是不可以的,所以关联式容器不能这样写。
下图揭示了上面的操作的本质,可见编译器为我们自动定义了一个_pos迭代器,然后每次执行decl=*_pos进行赋值。而当decl为引用时(也就是后面那个elem),const auto& elem = *_pos的意思是,让elem(elem是引用,引用在这里就是指针的含义)指向_pos这个地址(_pos是迭代器,本质上是地址的含义,STL源码分析中有介绍,),注意这里_pos前必须有*,别忘了C++中一个变量的引用是不能等于它的指针的哦,所以这里实际上不是拷贝赋值,这是高效的遍历方式。
这里加上const进行了只读保护,防止修改容器内部值。
由上一章知道explicit是禁止隐式转换,而这里在遍历过程中,存在类型不匹配(C和string),因此编译器默认去隐式转换,而C正好有一个参数类型对应的拷贝构造函数C(const string& s),可惜这里加了explicit,故而编译报错。