4

The C++ standard allows to bind const references to rvalues, therefore extending the lifetime of the temporary until the reference goes out of scope. However, I cannot figure out how this is actually compiled, let me explain with an example:

std::string foo() {
    return std::string("foo");
}

void bar() {
    VeryBigObject obj;
    // Perhaps do something with the big object
}

int main(int, char **) {
    const std::string &foo_str = foo();
    bar();
    return 0;
}

As far as I know, using an x86 architecture as an example, what happens there is that first the function foo() is called and the string object is constructed in the stack, which means that the needed amount of space is subtracted from the rsp register (assuming 64 bit architecture); afterwards, the rsp register is returned to its original value, freeing the stack space that the function foo() was filling, and, if I understand correctly, the call to bar() would use that stack space to construct the VeryBigObject, which would overwrite the string.

With all this in mind, how can the lifetime of the string be prolonged after the call to foo() in the assembly domain?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Samuel Navarro Lou
  • 1,168
  • 6
  • 17
  • My (informal) understanding of references is that C++ compilers transform them to pointers. – Bathsheba Dec 04 '14 at 14:56
  • It would be a very shoddy compiler if it behaves the way you describe it. – T.C. Dec 04 '14 at 14:57
  • 1
    @Bathsheba: Sometimes they're implemented like pointers; sometimes (like here) the referenced object is known to the compiler, so it can generate code to access it directly with no run-time indirection. – Mike Seymour Dec 04 '14 at 15:02

1 Answers1

7

The temporary return value will be constructed in the stack frame of main, either by copying/moving a temporary from that of foo or, more likely, using RVO to elide the copy and construct it directly in the caller's frame.

Once bound to a reference, the temporary will live as long as the reference. Effectively, the temporary is managed in exactly the same way that a named variable with the same scope would be.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • That is how I understand it needs to be done. My doubt here is with the standard, which specifies that RVO is optional, but however it guarantees that the reference effectively behaves as a reference, which means that **the referenced object won't be copied**. This essentially forces the compiler to use RVO, even though a stubborn compiler implementer decided not to, right? – Samuel Navarro Lou Dec 04 '14 at 17:02
  • 2
    @gdasamu: Without RVO, one temporary is created in the frame of `foo`, then copied/moved to create a second in the frame of `main` to form the function call result. With RVO, just one is created directly in `main`. In either case, the reference binds to the one in `main`. – Mike Seymour Dec 04 '14 at 17:07