2

I have the following code:

for (auto it = _locations.locations().begin(); it != _locations.locations().end(); ++it)
   // Do something

I wanted to replace it with

for (const auto& location: _locations.locations())
   // Do something

but then realized I don't know how it's going to work. Will the locations() method be called each iteration, or will the result of the container expression evaluation be "cached" locally, resulting in only one locations() call? Does the standard define this behavior one way or the other?

4
  • Did you consult the documentation? Commented Jan 21, 2016 at 20:06
  • @NathanOliver: I did consult with that very article. Didn't see it explicitly stated anywhere, although now I notice the auto && __range = range_expression ; line in the "Explanation" pseudocode. Commented Jan 21, 2016 at 20:09
  • Note that the code in @NathanOliver link is actually how it is specified in the standard, with notes that variable names are just for explanations sake. That isn't "Explanation pseudocode" as much as "a quote from the standard". Some of the clauses have results described by the standard, but a for-each loop in C++11 behaves as specified by that code block. Commented Jan 21, 2016 at 20:09
  • 1
    It also has If range_expression returns a temporary, its lifetime is extended until the end of the loop, as indicated by binding to the rvalue reference __range, but beware that the lifetime of any temporary within range_expression is not extended. Commented Jan 21, 2016 at 20:10

1 Answer 1

9

Yes, it's required to be "cached".

§[stmt.ranged]/1 says:

In each case, 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
              } 
}

So this requires that the begin-expr and end-expr each be invoked only once (though, of course, that's subject to the normal "as-if" rule, so this is subject to change if, for example, they have no observable side effects).

Sign up to request clarification or add additional context in comments.

3 Comments

... with the __ variables being merely exposition, and the result of the expressions being described elsewhere. In theory, begin-expr and end-expr could evaluate to objects that reinvoke .end() and .begin() on each != comparison, for example. (this is not the case unless you jump through some extreme hoops)
@Yakk: I don't even know how to achieve that. Thoughts?
@VioletGiraffe return iterators that wrap container that call begin/end each time. This is not a good idea: iterating over a container that mutates while you iterate will usually not work reliably, and when it fails it will fail in ways that are difficult to predict. Don't mutate containers as you iterate over them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.