WTF is going on here on a lower level?

const int& x = 3;

Simple one liner, but am a bit confused. Doesn't a const& store the address of an lvalue. So why does it work with rvalues.
Doesn't a const& store the address of an lvalue
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.
I think it's about the same as functions with const & parameters

1
2
3
4
5
6
7
8
9
void foo(const int& val) {}
void bar(int& val) {}

int main(void)
{
    foo(6); // valid
    bar(6); // invalid
    return 0;
}


Last edited on
""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

?
Last edited on
move '3' somewhere on the stack
more like "store it in read-only memory near other literals"

Also if function is inlined here, no passing would take place.
Source: http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c
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
Last edited on
""more like "store it in read-only memory near other literals"

Also if function is inlined here, no passing would take place.""

Interesting. I've checked and VC12 (not sure about others) seems to store it on the stack (no inlining specified). I guess that depends on compiler.
Last edited on
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.
This is what the standard specifies:

const int& x = 3;

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()
{
    const int& x = 3 ; // The reference 'r' is bound to an anonymous temporary object of type const int, which was copy-initialised with 3 
    
    const int* 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
}

http://coliru.stacked-crooked.com/a/046b14f586a417e5

Lifetime of the anonymous temporary object: http://en.cppreference.com/w/cpp/language/reference_initialization

"as-if": http://en.cppreference.com/w/cpp/language/as_if
Topic archived. No new replies allowed.