10

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
  • 108,238
  • 20
  • 242
  • 324
  • 1
    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
  • 1
    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

9

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
  • 249,747
  • 28
  • 448
  • 644
  • 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
8

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
  • 228,013
  • 71
  • 433
  • 510