Another pro I heard is the obvious time saved in typing less. But really, is the little saved time worth not making the loop clear?
In addition, the only con I read is that ranged-based for loops restrict the programmer to a specific range with no way to customize the condition.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
std::vector<char> Cstring;
for(auto iter = Cstring.begin(); iter != Cstring.end(); iter++)
//Clear that there is an iterator, a condition,
// and--if one knows how STL iterators works--that the return value is a
// pointer to a member in Cstring
for(char &value : Cstring)
//Clear that there is a value holder and the container is involved somehow
//Must have knowledge of how range-based loops work to understand what
// this vague statement means
//But what about multiple iterators and/or conditions?
//What about programmers who mistake the return value as a pointer just
// like the STL iterators and attempt to dereference the return value?
//Wouldn't a feature like this make the loop more clear:
// for(auto iter; Cstring.begin() : Cstring.end() )
Despite my doubts, I see everywhere programmers suggesting range-based loops like its the holy solution of most for loop issues.
I would really appreciate anyone helping me to understand why range-based loops are ultimately the better choice.
both your statement are (almost) equivalent.
Standard 6.5.4.1:
For a range-based for statement of the form
for ( for-range-declaration : expression ) statement
let range-init be equivalent to the expression surrounded by parentheses
( expression )
and for a range-based for statement of the form
for ( for-range-declaration : braced-init-list ) statement
let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to
[code]{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}[/code]
If called on array it will iterate from __range to __range + size.
If called on class it first will try to call __range.begin() and __range.end(). If not found: std::begin(__range) and std::end(__range).
Basically range-based loops created to iterate over all container as often encountered situation. If you need something other use old for loop.
EDIT: they allows to iterate over arrays, collections with methods begin() and end() and classes with overloaded std::begin() and std::end() with same syntax. You shouldn't care if sometimes vector might be replaced with array.
The major plus for range-based for loop is that it works with any range; any entity x for which std::begin(x) and std::end(x) are defined. So there is a uniform way to iterate over standard library containers, C-style arrays, initializer_lists. If we get a third-party user defined type that has the notion of a range of values, but does not provide standard library container style x.begin() and x.end(), we can still write our own std::begin(x) and std::end(x) overloads.
As a corollary, at least in generic code, prefer std::begin(x) and std::end(x) over x.begin() and x.end()
Cons of if statement is that in won't make coffee for me :)
And cons of ForwardIterator is that it cannot iterate backward
It was created to iterate forward (as Forward iterator is most supported one: all collections have it) over all collection (as most encountered situation).
You still can use normal for loops if you want something other than that. And I think boost has BOOST_REVERSE_FOREACH() function.
If you will think of range-based as of specialised for loop (which in turn just specialized while loop) it will make more sense.
don't offer the index of the current element
Neither is for(auto iter = Cstring.begin(); iter != Cstring.end(); iter++) do.
This is not cons of using range-based for in situation it was designed to be used in.
P.S. I jut thougt: you can write templated wrapper which will replace calls to begin() with rbegin() and end() with rend().
However it is an overkill. Better to manually write for loop.
It is easy to agree that a range-based loop for iterating in reverse might cone in handy in some situations.
Though trying to demonstrate its usefulness with an example of nextPermutation() that calls sort() twice inside an O(N) loop is counter-productive, to say the least.