0

If I try to return a string literal from a function, I can make these two versions:

std::string get_val()
{
    return "1234";
}

const std::string & get_ref()
{
    return "1234";
}

However, what confuses me is that I thought you need to have a long-lived object, in order to have an lvalue reference (I am reading const std::string & as an lvalue reference, perhaps I am mistaken).

Why does this work? Where does "1234" live after I return from the function?

Lou
  • 4,244
  • 3
  • 33
  • 72
  • 1
    I don't think it works, in fact GCC throws a warning for that code and if you try to call get_ref() it crashes https://www.jdoodle.com/iembed/v0/90U – Jack Lilhammers Feb 08 '21 at 11:56
  • 1
    Second version of `get_ref()` is invalid. It may seem to work but it is still invalid to return a reference to a local object. – ks1322 Feb 08 '21 at 11:58
  • 1
    What compiler and warning level (or lack thereof) are you using, where this isn't diagnosed? – underscore_d Feb 08 '21 at 12:03
  • Oh crap, it makes sense then. The problem is that `std::string & get_ref()` was a compiler error, but adding `const` passed the build and I didn't notice the warning. I am using gcc with -Wextra, but I just got confused and posted here too soon. Sorry everyone! – Lou Feb 08 '21 at 12:06
  • Related: https://stackoverflow.com/q/6441218/72178. – ks1322 Feb 08 '21 at 12:09
  • 1
    It may "work" until something has overwritten the carcass of a `std::string` that is decomposing where the temporary string used to be. Appearing to work is the most devious form of undefined behaviour. – molbdnilo Feb 08 '21 at 12:10
  • XD that's a nice way to describe it @molbdnilo, and coming from C it's completely logical. But I am just beginning C++ and reading about lvalue refs, rvalue refs and move/copy semantics is a rollercoaster of aha! and wtf? moments. – Lou Feb 08 '21 at 12:14

2 Answers2

1

The second implementation is not valid.

Actually return "1234" creates a temporary(rvalue) string object(as if it was return std::string("1234")) which resides on the stack, and as soon as it returns the returned reference becomes a dangling reference as it was on the stack memory.

Recent compilers would make a warning like:

https://godbolt.org/z/hWM76n

<source>: In function 'const string& get_ref()':
<source>:5:12: warning: returning reference to temporary [-Wreturn-local-addr]
    5 |     return "1234";
      |            ^~~~~~
Hanjoung Lee
  • 2,123
  • 1
  • 12
  • 20
1
std::string get_val()
{
    return "1234";
}

In this case an object of string type is created and then the move constructor(mostly will say a copy but due to compiler optimization move is more likely to be called ) is called to store the value in the destined variable

const std::string & get_ref()
{
    return "1234";
}

In this here you are returning a refrence to a temporary local object, so when the constructor of string done constructing the string object with "1234" and the return is called the object is destroyed after that as the object created was temporary with the local scope. It should throw an error to you

User
  • 572
  • 2
  • 10