Standard does not says how it should be implemented. It is up to compiler. Usually compilers are trying to eliminate any costs of references making it just an alias for another variable. For example in your case almost all instances of x would be replaced by 3 in compile time.
Standard also tells that const references prolong lifetime of temporaries as long as they exist. So conceptually "3" here is a rvalue which is not destroyed while x exist.
""Standard does not says how it should be implemented. It is up to compiler. Usually compilers are trying to eliminate any costs of references making it just an alias for another variable. For example in your case almost all instances of x would be replaced by 3 in compile time.
Standard also tells that const references prolong lifetime of temporaries as long as they exist. So conceptually "3" here is a rvalue which is not destroyed while x exist.""
Ah I see. So in a way, it is almost like a macro. Of course, if the compiler sees that you pass it to a function, then it would need to:
A) move '3' somewhere on the stack
B) pass that address to the function
Constant lvalue references can be assigned rvalues. Since they're constant, the value can't be modified through the reference and hence there's no problem of modifying an rvalue. This makes possible the very common C++ idiom of accepting values by constant references into functions, which avoids unnecessary copying and construction of temporary objects.
An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. [...] If T is a non-class type, the type of the rvalue is the cv-unqualified version of T. Otherwise, the type of the rvalue is T.
The second quote states that you can assign any T rvalue to a const T& because you can think of it as a const T&.
So, in your example, 3 gets converted to a const int with value 3 (not really but we can think of it as such) and therefore may be assigned to a const reference
edit: sorry, misread, but it worked for some reason when testing this principle
Yes. That depends on compiler, optimization options and moon phase.
This thread made me remember something. Well, it is not related to C++, but in FORTRAN there was no pass-by-value. Everything was passed by reference. So all literals were actually numbers set aside in memory (data area). And that memory could be changed too.
So things like
1 2
CALL SOMEFUNC (0)
FORMAT (I0)
might not pint 0 if SOMEFUNC changes value of passed argument. Or print 0 as at least one compiler had several zeroes and chose which to use next time somewhat arbitrary.
When this construct is compiled, the generated code behaves "as-if"
a. A temporary anonymous object of type const int is created and initialised with 3
(non-reference copy-initialisation: ie. const int anonymous_temporary = 3 ; ).
b. The reference is then bound to the this anonymous temporary object.
( const int& x = anonymous_temporary_from_step_a; ).
In other words, the reference does not bind directly to the prvalue (initializer expression).
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <iostream>
int main()
{
constint& x = 3 ; // The reference 'r' is bound to an anonymous temporary object of type const int, which was copy-initialised with 3
constint* p = &x ; // 'p' is of type 'pointer to const int', it holds the address of the anonymous temporary object
std::cout << p << ' ' // print the address of the anonymous temporary object of type const int
<< x << '\n' ; // print the address of the anonymous temporary object of type const int
// the expressions (x) and (*p) are lvalues of type const int
}