Search code examples
c++referencec++17temporary-objects

Is taking a reference from a temporary valid C++ code?


I used the following syntactic sugar:

for (auto& numberString: {"one", "two", "three", "four"}) { /* ... */}

Is this valid code? AFAIK, based on this question, this should be illegal, yet the code runs as expected. I don't think my understanding is correct on the matter.

As far as I know, only literals should not have memory addresses, yet the linked question is talking about temporaries and r-values.


Solution

  • Yes, this code is valid.

    Keep in mind that (for C++17), the compiler will semantically replace the range-based for loop by the construct

    {
    
        auto && __range = {"one", "two", "three", "four"};
        for (auto __begin = begin(__range), __end = end(__range); __begin != __end; ++__begin)
        {
    
            auto& numberString = *__begin;
            /* ... */
        }
    
    }
    

    You see, the lifetime of the initializer_list is extended to the lifetime of __range inside of the outermost scope in the replacement.

    Note however that you still can easily cause undefined behavior if the range expression contains a temporary itself:

    struct some {
       auto get_list() { return {"one", "two", "three", "four"}; }
    };
    
    some foo() { return some{ }; }
    
    for(auto& numberString : foo().get_list()) { /* ... */ }
    

    The above code will result in a dangling reference in <= C++20. Only in C++23, the lifetime of the temporary created by foo() will get extended such that it becomes valid. See also https://en.cppreference.com/w/cpp/language/range-for