0
std::vector<std::string> func(int num) {
  std::vector<std::string> vec;
  int sum = 0;
  for(int i = 0; i < num; i++) {
    sum +=i;
    std::string s = std::to_string(sum);
    vec.emplace_back(s);
  }
  return vec;
}

what's the difference between the code below about using rvalue and lvalue reference.

  std::vector<std::string> res = func(10);      // (case 1)
  std::vector<std::string> &&res = func(10);    // (case 2)
  std::vector<std::string> &res = func(10);   // I got an error!, case3
  const std::vector<std::string> &res = func(10);  // case4

Question:

  1. can the rvalue reference(case 2) save a memory copy? than case1
  2. why lvalue reference(case3) got an error but it work with the const (case4)?
Andy
  • 1
  • 1
    In answer to your question 2: [Why is it allowed to pass R-Values by const reference but not by normal reference?](https://stackoverflow.com/q/36102728/2602718) – scohe001 Feb 05 '21 at 20:57

2 Answers2

1
  1. When a prvalue (a "temporary") is bound to an rvalue reference or a const lvalue reference, the lifetime of the temporary is extended to the lifetime of the reference.
  2. a non-const lvalue reference does not extend the lifetime of a prvalue.

can the rvalue reference(case 2) save a memory copy? than case1

It preserves the lifetime of the single returned object. See 1.

why lvalue reference(case3) got an error

See 2.

but it work with the const (case4)?

See 1.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • Thanks for your clear answer! then how about the rvalue ref return type? LIke: std::vector &&func(int num) { return std::move(vec); } what's the diff between case2? – Andy Feb 05 '21 at 21:16
  • @eerorika I struggled to read that many times, but I think you're correct about what "memory copy" means here. Yes, it saves-preserves the "copy" that's in memory. No it doesn't save-prevent an additional copy to new memory. – Drew Dormann Feb 05 '21 at 21:44
  • @DrewDormann Ooh, I think I see how you interpret the question. Yeah, it's quite unclear. The "than case1" leads me to believe that the question is whether case 2 avoids a copy that case 1 has. – eerorika Feb 05 '21 at 21:46
  • @Andy an rvalue ref return type is **not** a prvalue, so no lifetime extension occurs under any of those circumstances. This lifetime extension is only for prvalues. – Drew Dormann Feb 05 '21 at 21:49
  • @DrewDormann Sorry for the poor writing, I even't didn't know the term prvalue and xrvalue before, learned! Thanks for your detailed reply! – Andy Feb 06 '21 at 08:51
0
  1. can the rvalue reference(case 2) save a memory copy? than case1

If you mean, "does case 2 avoid some copy that case 1 has", then the answer is: No. Both are effectively identical if res is an automatic variable. I recommend writing the case 1 because it is simpler and less confusing.

Firstly, there is a move from vec to the returned value. In practice, this move can be elided by an optimiser. Such optimisation is known as NRVO (Named Return Value Optimisation).

Since C++17: The is initialised directly by the move mentioned above (which may have been elided) in both cases.

Pre-C++17: There is another move from the return value to the initialised object in both cases. This move can also be elided in practice.

  1. why lvalue reference(case3) got an error but it work with the const (case4)?

Because lvalue references to non-const may not be bound to rvalues.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • for c++17, do you mean it's the perfect one, say the compiler will just use the memory in the function scope extending to outside of the func, there is no copy or move? – Andy Feb 05 '21 at 21:36
  • @Andy If the NRVO is done to get rid of the first move, then there will not be any moves. – eerorika Feb 05 '21 at 21:37
  • I got it, thanks so much for your detailed answer! – Andy Feb 06 '21 at 08:52