Does a C++11 range-based for loop condition get evaluated every cycle?
It is only evaluated once. The standard defines a range-based for
statement as equivalent to:
{
auto && __range = range-init;
for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
where range-init
is the expression (surrounded by parentheses) or braced-init-list after the :
C++11 range-based for() loops evaluate once or multiple times?
It is evaluated only once. The standard says that the range-based for loop is equivalent to this:
§6.5.4 The range-based for statement [stmt.ranged]
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
with range-init
being equivalent to ( bar() )
in your case (the expression you specify, surrounded by parenthesis). That expression is only evaluated once as you can see.
How do Range-Based for loops handle temporary containers
get_vector()
is evaluated once, and the result is stored in a temporary.
6.5.4/1 ...a range-based for statement is equivalent to
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
In your example, range-init
would be (get_vector())
.
Is statement in for each loop executed each iteration?
The range-based for loop is equivalent as follows:
{
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
Note the 1st statement auto && __range = range_expression ;
(range_expression
will be GenerateRandomContainer()
for your code); that means the Container
will be generated only once, and iterates on all the elements of it.
Is the expression in a ranged-for statement evaluated on each iteration?
No, only once.
[C++11: 6.5.4]:
For a range-basedfor
statement of the formfor ( for-range-declaration : expression ) statement
let range-init be equivalent to the expression surrounded by parentheses
( expression )
[..] a range-based for statement is equivalent to
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
[..]
Interestingly, this relatively new passage is a rare example of the standard defining semantics in terms of code using pre-existing language features. I guess they got bored of writing terse technical language.
It means we have to deduce the fact above from the code; in this case, fortunately, it's easy: range-init is evaluated once and bound to the universal reference __range
.
Is c++11 range-for not equal to classic for in terms of functionality?
First loop prints the message 10 times, second one prints it only once.
That's right, because in the first loop you've asked the compiler to create a new Range
to compare the iterator to each time you enter the loop.
Are they not equal?
No
Can this difference complicate old code revision?
Not usually. It's just that you've created a contrived example.
In a loop, do any operations in the end-condition get evaluated in every iteration?
It obviously depends on the language. For JavaScript, the spec (ECMAScript §12.6.3) requires it always be evaluated each time. As an optimization, a specific JavaScript runtime could skip one or more of the length calls, if it could prove that the result would not change.
How can I avoid for loops with an if condition inside them with C++?
IMHO it's more straight forward and more readable to use a for loop with an if inside it. However, if this is annoying for you, you could use a for_each_if
like the one below:
template<typename Iter, typename Pred, typename Op>
void for_each_if(Iter first, Iter last, Pred p, Op op) {
while(first != last) {
if (p(*first)) op(*first);
++first;
}
}
Usecase:
std::vector<int> v {10, 2, 10, 3};
for_each_if(v.begin(), v.end(), [](int i){ return i > 5; }, [](int &i){ ++i; });
Live Demo
Is it safe to use a C++11 range-based for-loop with an rvalue range-init?
Yes, it's perfectly safe.
From [class.temporary]/4-5:
There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called [...]
The second context is when a reference is bound to a temporary. The temporary to which the reference is
bound or the temporary that is the complete object of a subobject to which the reference is bound persists
for the lifetime of the reference except:
- A temporary bound to a reference member in a constructor’s ctor-initializer [...]
- A temporary bound to a reference parameter in a function call [...]
- The lifetime of a temporary bound to the returned value in a function return statement [...]
- A temporary bound to a reference in a new-initializer [...]
None of those exceptions apply. The temporary thus persists for the lifetime of the reference, __range
, which is the entire loop.
C for loop implemented differently than other languages?
Consider this:
for i:=0 to 100 do { ... }
In this case, we could replace the final value, 100, by a function call:
for i:=0 to final_value() do { ... }
... and the final_value
-function would be called only once.
In C, however:
for (int i=0; i<final_value(); ++i) // ...
... the final_value
-function would be called for each iteration through the loop, thus making it a good practice to be more verbose:
int end = final_value();
for (int i=0; i<end; ++i) // ...
Related Topics
Why Floating Point Value Such as 3.14 Are Considered as Double by Default in Msvc
In C++ , What's So Special About "_Move_H"
Nested Templates with Dependent Scope
What Is Uint_Fast32_T and Why Should It Be Used Instead of the Regular Int and Uint32_T
C++ Qt Signal and Slot Not Firing
Why Does Gcc Generate 15-20% Faster Code If I Optimize for Size Instead of Speed
Waitpid Equivalent with Timeout
Does Static Constexpr Variable Inside a Function Make Sense
What Is Better, Adjacency Lists or Adjacency Matrices for Graph Problems in C++
Are Parentheses Around the Result Significant in a Return Statement
Does the C++ Volatile Keyword Introduce a Memory Fence
Order of Execution in Constructor Initialization List
Near Constant Time Rotate That Does Not Violate the Standards
Where Are Temporary Object Stored
Why Should Default Parameters Be Added Last in C++ Functions