25

In the latest C++ standard it implies that:

for (foo : bar)
    baz;

is equivilant to:

{
    auto && r = bar;
    for ( auto it = r.begin(), end = r.end(); it != end; ++it )
    {
        foo = *it;
        baz;
    }
}

When bar in the above is a function call that returns a collection, eg:

vector<string> boo();

ie

for (auto bo : boo())
    ...

Doesn't the line become:

auto&& r = boo();
...

And so the temporary return value of boo() is destroyed at the end of the statement "auto&&r=boo()", and then r is a hanging reference at the entry of the loop. ?? Is this reasoning correct? If not, why not?

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • 1
    First of all, `vector boo();` does NOT declare an object. It declares a function. Second, I don't understand your question. – Nawaz Mar 11 '12 at 18:37
  • 11
    Yes "vector boo()" is the signature of an example function that returns a collection. The function is then called in the line below. – Andrew Tomazos Mar 11 '12 at 18:38

2 Answers2

24

Is this reasoning correct? If not, why not?

It is correct up until this point:

And so the temporary return value of boo() is destroyed at the end of the statement "auto&&r=boo()" [...]

Binding a temporary to a reference extends its lifetime to be that of the reference. So the temporary lasts for the whole loop (that's also why there is an extra set of {} around the whole construct: to correctly limit the lifetime of that temporary).

This is according to paragraph 5 of §12.2 of the C++ standard:

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:

[various exceptions that don't apply here]

This is an interesting property that allows abusing the ranged-for loop for non-rangey things: http://ideone.com/QAXNf

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
9

The reasoning is not correct because boo returns a temporary object by value. Binding this temporary object to a reference implies that the lifetime of the temporary is extended. Standard quote (§ 12.2/5):

[…] 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 […]

The reasoning would be correct if boo returned a reference. An example for an expression returning a reference to a temporary is string("a") += string("b"); using this value in a range-based for loop gives rise to undefined behavior.

Philipp
  • 48,066
  • 12
  • 84
  • 109