9

According to another answer, an rvalue reference will not extend the lifetime of a temporary if the expression referring to it is an xvalue expression. Since std::move returns an rvalue reference, the expression of calling it is an xvalue and so the following results in an a dangling reference:

int main()
{
  std::string&& danger = std::move(get_string());  // dangling reference !
  return 0;
}

That's fine. The std::move doesn't make sense here; it is already an rvalue.

But here's where I'm drawing a blank. How is this different to passing an xvalue expression as an argument, completely standard use of std::move and rvalue references?

void foo(const std::string& val);
// More efficient foo for temporaries:
void foo(std::string&& val);

int main()
{
  std::string s;
  foo(std::move(s)); // Give up s for efficiency
  return 0;
}

Is there a special rule for rvalue reference arguments that will extend the lifetime of a temporary regardless of whether it is an prvalue or xvalue? Or is the std::move calling expression only an xvalue because we passed it something that was already an rvalue? I don't think so because it returns an rvalue reference anyway, which is an xvalue. I'm confused here. I think I'm missing something silly.

Community
  • 1
  • 1
Joseph Mansfield
  • 104,685
  • 19
  • 232
  • 315
  • Unrelated: if the function `foo` is going to copy or move either way, you may want to just take the argument by value and let the compiler do the copy or move. – R. Martinho Fernandes Nov 27 '12 at 13:30
  • A note about your first example: `std::move(get_string())` is no longe a temporary expression. The temporary expression was `get_string()`, but then you cast it. So the rule about a temporary expression binding to a reference no longer applies. – Kerrek SB Nov 27 '12 at 13:38

2 Answers2

8

Your second example is not passing a reference to a temporary, it's passing a reference to the variable s, which lasts until the end of main().

If it were (e.g. foo(std::move(get_string()));), then the temporary's lifetime lasts until the end of the full expression - after the function has returned. It's therefore quite safe to use it within foo. There is only a danger if foo stores a reference/pointer to its argument, and something else tries to use it later.

Mike Seymour
  • 242,813
  • 27
  • 432
  • 630
  • 1
    But it is illegal to take addresses of rvalues. – user1095108 Jul 21 '13 at 03:02
  • 4
    @user1095108 but `val` is not an rvalue within the body of the function `foo(std::string&& val)`. It is an lvalue of type "rvalue reference". Perfectly legal to take its address, and use its address, until the lifetime of `s` ends. – Oktalist Apr 02 '14 at 11:31
7

There is no need to extend any lifetime here: the object in question lasts until the end of main, which is after the end of foo.

R. Martinho Fernandes
  • 219,040
  • 71
  • 423
  • 503