The code exhibits undefined behavior - the function test_const_ref
returns a reference to a temporary, which lives until the end of the full-expression (the ;
), and any dereference of it afterwards accesses a dangling reference.
Appearing to work is a common manifestation of UB. The program is still wrong. With optimization on, for example, Clang 12 -O2 prints: 0
.
Note - there's no error in the function test_const_ref
itself (apart from a design error). The UB is in main
, where the dereference of the dangling int&
happens during a call to printf
.
Where the temporary int
is stored exactly is implementation detail - but in many cases (in a Debug build, when a function isn't inlined), it would be stored on the stack:
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov dword ptr [rbp - 12], 1 # Here the 1 is stored in the stack frame
lea rdi, [rbp - 12]
call test_const_ref(int const&)
mov qword ptr [rbp - 8], rax
mov rax, qword ptr [rbp - 8]
mov esi, dword ptr [rax]
mov rdx, qword ptr [rbp - 8]
movabs rdi, offset .L.str
mov al, 0
call printf
So any subsequent use of the returned reference will access memory at [rbp - 12]
, that may already have been re-used for other purposes.
Note also that the compiler doesn't actually generate assembly from C++ code; it merely uses the C++ code to understand the intent, and generates another program that produces the intended output. This is known as the as-if rule. In the presence of undefined behavior, the compiler becomes free from this restriction, and may generate any output, rendering the program meaningless.