2

The logic of the following is confusing me. It compiles ok but the result of foo is an rvalue. It is a temporary. Why am I then allowed to get non constant references to items in the container?

https://godbolt.org/z/vEafrE

#include <array>

std::array<int,3> foo(){
    return std::array<int,3>{0,1,2};
}

int main(){
    for(int & item: foo())
        item = 0;
}

1
  • Probably because the lifetime of the container is long enough to survive the loop contents and thus that reference is safe to use within that loop. Commented Feb 15, 2021 at 14:34

1 Answer 1

4

The range based for loop has the syntax

attr(optional) for ( init-statement(optional)range_declaration : range_expression ) loop_statement

and it expands into

{
    init-statement
    auto && __range = range_expression ;
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {
        range_declaration = *__begin;
        loop_statement
    }
}

as you can see, the rvalue's lifetime gets extended by __range, so it's valid to have lvalue references into the collection __range binds to. Once the loop is over, __range will go out of scope destroying the rvalue object that was created.

This is why it works even though you are modifying an object that is destined to be destroyed.

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

Comments

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.