C++11 range-based for loops
2014-03-26 12:08
302 查看
In the first article introducing C++11 I
mentioned that C++11 will bring some nice usability improvements to the language. What I mean is that it removes unnecessary typing and other barriers to getting code written quickly. One example I've already covered is the new meaning of the auto
keyword; now I'd like to talk more about the range-based for loop--both how to use it, and how to make your own classes work with it.
and it will iterate over it. We've already seen a few basic examples in What is C++11? To refresh your memory,
the range-based for loop looks like this:
This code prints the contents of a vector called
vec, with the variable i taking on the value of each element of the vector, in series, until the end of the vector is reached.
You can use auto in the type, to iterate
over more complex data structures conveniently--for example, to iterate over a map you can write
And you don't need to worry about spelling out the iterator type.
Modifying the Contents of the Vector
If you want to modify the values in the container you're looping over, or if you want to avoid copying large objects, and the underlying iterator supports it, you can make the loop variable
a reference. For example, here's a loop that increments each element in an integer vector:
and all STL containers can be iterated over with the new range-based for loop already. But what if you want
to allow your own data structures to use the new syntax?
In order to make a data structure iterable, it must work similarly to the existing STL
iterators.
There must be begin and end methods that operate on that structure, either as members or as stand-alone functions, and that return iterators to the beginning and end of the structure
The iterator itself must support an operator* method, an operator != method, and an operator++ method, either as members or as stand-alone functions (you can read more about operator
overloading)
Note that operator++ should be the prefix version, which is done by declaring a function called operator++ that takes no arguments.
That's it! With these five functions, you can have a data structure that works with a range-based for loop. Because the begin and end methods can be non-member functions ( begin( container
) instead of container.begin() ), you can even adapt existing data structures that don't natively support the STL-style iterators. All you must do is create your own iterator that supports *, prefix increment (++itr) and != and that has a way of defining a
begin iterator and an end iterator.
Since range-based for loops are so nice, I suspect that most new containers that don't already support the STL iterator model will want to add adaptors of some sort that allow range-based
for loops to be used. Here's a small program that demonstrates creating a simple iterator that works with a range-based for loops. In it, I create an IntVector type that is fixed at a size of 100, and that can be iterated over using a class called Iter. I've
made this code const-correct, but if you haven't seen that concept before, the code works just fine with
every const removed.
this easily by changing the return value of get to be a reference, but this would make the code much longer by requiring the addition of non-const methods, and I wanted to focus on the basic structure.
Do range-based for loops increase performance?
In my limited testing with GCC 4.6, I did not see a performance improvement in range-based for loops over normal STL iteration, but it seems like it should be possible for range-based for
loops to see the same performance improvements as the STL's for_each function, which has the same model of iterating over a container in iterator order.
loops, I had to install GCC 4.6 from source; I found this article useful for doing so under Cygwin.
You can also find pre-built MinGW binaries with GCC 4.7 on this page.
from http://www.cprogramming.com/c++11/c++11-ranged-for-loop.html
mentioned that C++11 will bring some nice usability improvements to the language. What I mean is that it removes unnecessary typing and other barriers to getting code written quickly. One example I've already covered is the new meaning of the auto
keyword; now I'd like to talk more about the range-based for loop--both how to use it, and how to make your own classes work with it.
Basic syntax for range-based for loops
Nowadays, almost every programming language has a convenient way to write a for loop over a range of values. Finally, C++ has the same concept; you can provide a container to your for loop,and it will iterate over it. We've already seen a few basic examples in What is C++11? To refresh your memory,
the range-based for loop looks like this:
vector<int> vec; vec.push_back( 10 ); vec.push_back( 20 ); for (int i : vec ) { cout << i; }
This code prints the contents of a vector called
vec, with the variable i taking on the value of each element of the vector, in series, until the end of the vector is reached.
You can use auto in the type, to iterate
over more complex data structures conveniently--for example, to iterate over a map you can write
map<string, string> address_book; for ( auto address_entry : address_book ) { cout << address_entry.first << " < " << address_entry.second << ">" << endl; }
And you don't need to worry about spelling out the iterator type.
Modifying the Contents of the Vector
If you want to modify the values in the container you're looping over, or if you want to avoid copying large objects, and the underlying iterator supports it, you can make the loop variable
a reference. For example, here's a loop that increments each element in an integer vector:
vector<int> vec; vec.push_back( 1 ); vec.push_back( 2 ); for (int& i : vec ) { i++; // increments the value in the vector } for (int i : vec ) { // show that the values are updated cout << i << endl; }
What does it mean to have a range?
Strings, arrays,and all STL containers can be iterated over with the new range-based for loop already. But what if you want
to allow your own data structures to use the new syntax?
In order to make a data structure iterable, it must work similarly to the existing STL
iterators.
There must be begin and end methods that operate on that structure, either as members or as stand-alone functions, and that return iterators to the beginning and end of the structure
The iterator itself must support an operator* method, an operator != method, and an operator++ method, either as members or as stand-alone functions (you can read more about operator
overloading)
Note that operator++ should be the prefix version, which is done by declaring a function called operator++ that takes no arguments.
That's it! With these five functions, you can have a data structure that works with a range-based for loop. Because the begin and end methods can be non-member functions ( begin( container
) instead of container.begin() ), you can even adapt existing data structures that don't natively support the STL-style iterators. All you must do is create your own iterator that supports *, prefix increment (++itr) and != and that has a way of defining a
begin iterator and an end iterator.
Since range-based for loops are so nice, I suspect that most new containers that don't already support the STL iterator model will want to add adaptors of some sort that allow range-based
for loops to be used. Here's a small program that demonstrates creating a simple iterator that works with a range-based for loops. In it, I create an IntVector type that is fixed at a size of 100, and that can be iterated over using a class called Iter. I've
made this code const-correct, but if you haven't seen that concept before, the code works just fine with
every const removed.
#include <iostream> using namespace std; // forward-declaration to allow use in Iter class IntVector; class Iter { public: Iter (const IntVector* p_vec, int pos) : _pos( pos ) , _p_vec( p_vec ) { } // these three methods form the basis of an iterator for use with // a range-based for loop bool operator!= (const Iter& other) const { return _pos != other._pos; } // this method must be defined after the definition of IntVector // since it needs to use it int operator* () const; const Iter& operator++ () { ++_pos; // although not strictly necessary for a range-based for loop // following the normal convention of returning a value from // operator++ is a good idea. return *this; } private: int _pos; const IntVector *_p_vec; }; class IntVector { public: IntVector () { } int get (int col) const { return _data[ col ]; } Iter begin () const { return Iter( this, 0 ); } Iter end () const { return Iter( this, 100 ); } void set (int index, int val) { _data[ index ] = val; } private: int _data[ 100 ]; }; int Iter::operator* () const { return _p_vec->get( _pos ); } // sample usage of the range-based for loop on IntVector int main() { IntVector v; for ( int i = 0; i < 100; i++ ) { v.set( i , i ); } for ( int i : v ) { cout << i << endl; } }One thing to notice about this code is that it does not allow modification of elements in the IntVector by using a reference in the for loop. You should be able to add
this easily by changing the return value of get to be a reference, but this would make the code much longer by requiring the addition of non-const methods, and I wanted to focus on the basic structure.
Do range-based for loops increase performance?
In my limited testing with GCC 4.6, I did not see a performance improvement in range-based for loops over normal STL iteration, but it seems like it should be possible for range-based for
loops to see the same performance improvements as the STL's for_each function, which has the same model of iterating over a container in iterator order.
Compiler availability
Unfortunately, range-based for loops are not all that well supported. MSVC only added support in version 11, and GCC only added support in version 4.6. In order to test out range-based forloops, I had to install GCC 4.6 from source; I found this article useful for doing so under Cygwin.
You can also find pre-built MinGW binaries with GCC 4.7 on this page.
from http://www.cprogramming.com/c++11/c++11-ranged-for-loop.html
相关文章推荐
- 一些C++11语言新特性 - Range-Based for Loops
- C++11 性能Range-based for loops
- C++11新特性之四:range-based for loops
- C++11 新特性之Range-based for loops
- C++11中range-based for loops中&&与&的区别
- C++11新特性之基本范围的For循环(range-based-for)
- c++11 : range-based for loop
- C++ 11 学习2:空指针(nullptr) 和 基于范围的for循环(Range-based for loops)
- 自定义类型使用range-based for loops
- Range-Based for Loops
- c++11 : range-based for loop
- C++ 11 学习2:空指针(nullptr) 和 基于范围的for循环(Range-based for loops)
- C++11 | range-based for loop
- C++11中的有趣的新特性(constexpr ) (Range-based for loop)
- C++11新特性:range based for loop-范围for循环基本使用方法
- C++11 Range for Statement
- How to change mode from c++98 mode in Dev-C++ to a mode that supports C++0x (range based for)?
- Code::Blocks error: range-based 'for' loops are not allowed in C++98 mode
- 关于C++11 range-for的一个陷阱
- Modern C++(二)Range-based for loop(基于范围的for循环)