1

I'm wondering if the following is valid:

#include <iostream>
#include <vector>

std::vector<int>& getVec()
{
    static std::vector<int> vec{1, 2, 3, 4, 5};
    return vec;
}

int main()
{
    for (const auto& i : getVec())
    {
        std::cout << "i = " << i << std::endl;
    }
    return 0;
}

Basically I'm unsure about the lifetime of the temporary from getVec(). I've looked at both this post and this one, but am in a bit of a different situation as my function returns a reference to static data. Specifically, I'm wondering if scenario violates the following exception in the stated rule:

  • A temporary bound to a reference parameter in a function call [...]

or if this is indeed safe code. I think it is safe, but just wanted to be sure.

zeus_masta_funk
  • 1,388
  • 2
  • 11
  • 34
  • 8
    There is no temporary vector here. You are just iterating over `getVec`'s `vec`. – François Andrieux May 31 '18 at 19:09
  • Ok, I was a bit confused and though maybe the range based for loop was creating a temporary reference to the `vector` returned in `getVec`. Thanks for the clarification. Post an answer if you'd like and I'll mark it as the answer. – zeus_masta_funk May 31 '18 at 19:15
  • the range based for loop basically just calls `begin()` and `end()` and exapnds to an iterator based loop. see eg [here](https://en.cppreference.com/w/cpp/language/range-for) – 463035818_is_not_an_ai May 31 '18 at 19:25

1 Answers1

2

Yes, this is fully valid and well-defined.

The range-based for loop in your question is defined to be equivilent to the following, for imaginary variables range, begin, and end:

auto&& range = getVec();
auto begin = std::begin(range);
auto end = std::end(range);
for (; begin != end; ++begin)
{
    const auto& i = *begin;
    {
        std::cout << "i = " << i << std::endl;
    }
}

After reference collapsing rules are applied, the type of range becomes std::vector<int>&. That means no temporaries are ever created. The loop iterates over the static vector defined in getVec.

If getVec instead returned by value, the type of range would be std::vector<int>&&, and lifetime extension would be applied. That would extend the lifetime of the temporary object to that of the reference, and everything would still be totally valid.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52