0

Can someone explain whether this is ok or not?

#include <iostream>
#include <vector>

struct A {
    std::vector<int> numbers;
    ~A() {std::cout << "A destroyed.\n";}
    const std::vector<int>& getNumbers() const {return numbers;}
    std::vector<int> getNumbersByValue() const {return numbers;}
};

std::vector<int> foo() {
    A a;
    a.numbers = {1,2,3,4,5};
//  return a.getNumbersByValue();  // This works of course.
    return a.getNumbers();  // Is this line wrong?
}

void useVector(std::vector<int>& v) {
    for (int i = 6; i <=10; i++)
    v.push_back(i);
}

int main() {
    auto v = foo();  // A destroyed.
    for (int x : v) std::cout << x << ' ';  // 1 2 3 4 5
    std::cout << '\n';

    useVector(v);
    for (int x : v) std::cout << x << ' ';  // 1 2 3 4 5 6 7 8 9 10
}

Since a is destroyed in foo(), then a.numbers is destroyed too, right? If foo() returns a copy of a.numbers, using A::getNumbersByValue(), then everything is fine. But above I'm using getNumbers(), which returns it by reference. The vector still survives after foo() ends. So I pass the vector into the function useVector to see if it still survives, and it does. So is everything ok here?

prestokeys
  • 4,817
  • 3
  • 20
  • 43
  • 1
    But `v` is a copy. So there's no problem. In any case, you're not returning a reference to a destroyed object anywhere. – juanchopanza Dec 30 '14 at 21:00
  • @juanchopanza. If I replace return std::make_pair(v, 'k'); with return std::make_pair(a.getNumbers(), 'k');, everything works fine too. – prestokeys Dec 30 '14 at 21:00
  • That's because it does the same thing essentially. – tom Dec 30 '14 at 21:01
  • 1
    You would have problem with `std::vector& foo()` (reference added). – Jarod42 Dec 30 '14 at 21:05
  • I changed the question and got rid of std::pair altogether. The above code is still fine? It would only be a problem if foo() returns `std::vector?` right? Hence `A::getNumbersByValue()` is totally unnecessary. – prestokeys Dec 30 '14 at 21:06
  • Yes, it is fine. To quote my previous comment, "you're not returning a reference to a destroyed object anywhere." – juanchopanza Dec 30 '14 at 21:10
  • Ok, I got it now. Thanks. – prestokeys Dec 30 '14 at 21:11
  • See also http://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement – IdeaHat Dec 30 '14 at 21:23

1 Answers1

3

Since foo returns its return value by value (not by reference), foo makes a copy of the vector to return. It copies from the reference it got back from getNumbers as part of the return before it destroys the local variable a, so at the time it makes the copy, the reference is still valid.

So this code is fine.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • To add on, most compilers will do RVO and thus skip the copy all together. In cases where this is not possible, C++11 will use the move constructor. Yay! – IdeaHat Dec 30 '14 at 21:22