5
#include <iostream>
int foo()
{
  return 0;
}

int main()
{
  const int& a = foo();
  std::cout << &a << std::endl;
}

In this code, a binds to a rvalue. Is it legal to take its address? (And by legal I mean: in the code ill-formed? Am I causing an undefined behaviour?)

qdii
  • 12,505
  • 10
  • 59
  • 116
  • I would say it's ok because the temporary lives as long as the const reference that it's bound to, so printing the address of that should be fine. I can't reference that yet, though. – chris Nov 08 '12 at 00:09
  • @chris: what about the cases when the value is returned in a register rather than the stack? – qdii Nov 08 '12 at 00:09
  • It looks like well formed code with defined behavior to me. "The temporary to which the reference is bound or the temporary that is the complete object of a sub-object to which the reference is bound persists for the lifetime of the reference..." In other words, at that point the value is pretty much like any other local. – Jerry Coffin Nov 08 '12 at 00:09
  • @qdii, I thought about that, but when you take the address, I would imagine it has to be stuck in memory for that. When you think about it, the compiler can put whatever variables it wants in the registers and not keep them in memory. Therefore, this would be equivalent to taking the address of any other variable in that regard. – chris Nov 08 '12 at 00:10
  • 1
    @qdii: That's an implementation detail not relevant to you. The compiler needs to do whatever it takes to make the code work, and if that means not using a register then so be it. – GManNickG Nov 08 '12 at 00:18

2 Answers2

6

This is fine. In C++11 you can even do this:

int&& a = foo();
a = 123;

You can kind of think about temporaries like this (conceptually and in general):

x = func(); // translated as:

auto __temporary = func();
x = __temporary;
__destruct_value_now_and_not_later(__temporary);

Except if x is the definition of a reference type, the compiler notes that you're purposefully referring to the temporary value and extends its lifetime by removing the early destruction code, making it a normal variable.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • The lifetime is only extended for references to const values, I believe. – Nemo Nov 08 '12 at 00:19
  • @GManNickG : Well, not _any_ reference (e.g. non-const lvalue reference), but it is for `&&`. – ildjarn Nov 08 '12 at 00:22
  • How would this be implemented, where the callee allocates space on the stack for a variable but does not deallocate it all depending on what the caller assigns the result to? – Seth Carnegie Nov 08 '12 at 00:24
  • @SethCarnegie: Sorry, I don't follow. Note this is only a generalization omitting details, purposefully; how it's actually implemented doesn't affect the idea. Generally the caller is responsible for providing the space for the return value (assuming it won't fit in a register, which both the caller and callee know a priori). – GManNickG Nov 08 '12 at 00:31
  • @GManNickG oh you're right, I was thinking of something irrelevant. Do you know what section of the standard is this in (the extension of the lifetime of temporaries)? – Seth Carnegie Nov 08 '12 at 00:32
3

Yes. Until the variable a goes out of scope, the temporary it captures is valid. Herb Sutter can explain it better.

moswald
  • 11,491
  • 7
  • 52
  • 78