I am interested in how the following code:
int&& c = 2;
c++;
std::cout << c; //3
keeps the variable 'c' in memory?
How the compiler implements the reference at the machine level? Does it set aside any memory for it? If so, where? Or it keeps it in CPU register?
Whether or not a reference is bound to a lifetime-extended temporary is a property that is determined at compile-time for the specific reference.
For example in
{
int x = 2;
int&& c = std::move(x);
c++;
std::cout << c; //3
}
the value category of std::move(x)
is xvalue and therefore it doesn't result in the creation of a temporary whose lifetime would be extended.
On the other hand in
{
int&& c = 2;
c++;
std::cout << c; //3
}
the initializer expression 2
is a prvalue. A prvalue needs to be materialized into a temporary to which the reference can bind. Because the materialization happens directly before binding the reference, the lifetime of the temporary is extended to match that of the reference.
Effectively, the two snippets do the same thing and the compiler can simply transform the second one into the first one. Consequently the usual rules for storage of objects apply. The int
object (either the variable or the temporary) will typically be stored on the stack or in a register depending on whether the compiler will end up needing it to have an address. The reference is typically implemented similar to a pointer, also on the stack or in a register.
However, in such a simple example, the compiler doesn't need to store the reference at all, since it knows where the variable or temporary which the reference references is stored in the function. In machine instructions all uses of the reference can simply be replaced with memory or register references to the object.
Practically speaking the snippet will then be equivalent to
{
int c = 2;
c++;
std::cout << c; //3
}
Furthermore, usual optimizations apply and the compiler will in the case in your question simply do constant-propagation and see that you are just outputting the same number all the time. Instead of storing either the variable or the reference, it can just optimize the whole thing to std::cout << 3;
.