1

In the code below,

int firstFunction(int& refParam)
{
    std::cout << "Type of refParam is: " << typeid(refParam).name() << '\n';
    return refParam;
}

int secondFunction(int param)
{
    std::cout << "Type of param is: " << typeid(param).name() << '\n';
    return param;
}

int main()
{
    int firstVar{ 1 };
    int secondVar{ firstFunction(firstVar) };
    int thirdVar{ secondFunction(firstVar) };
}

Console output is

int
int

When i check the assembly code in Godbolt link.

firstFunction(int&):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        pop     rbp
        ret
secondFunction(int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     eax, DWORD PTR [rbp-4]
        pop     rbp
        ret

reference parameter creates a space of 8 bytes QWORD PTR [rbp-8], rdi instead of 4 bytes in second function DWORD PTR [rbp-4], edi

After seeing eax, DWORD PTR [rax] in line 6 in firstFunction(int&): I thought it might be because the first half(eax) stores the value adress but when i create a third function have char& as parameter it also creates 8 byte space. Godbolt Link

Is there any reason for that?

Aamir
  • 1,974
  • 1
  • 14
  • 18
UPinar
  • 1,067
  • 1
  • 2
  • 16
  • Because pointers are 8 bytes, and you compiled without optimization so it spills the incoming stack args. References are just pointers in asm. – Peter Cordes Jan 08 '23 at 14:10
  • @PeterCordes yea i thought that but when i print types of them in visual studio they both are `int` – UPinar Jan 08 '23 at 14:12
  • 1
    That's in C++, where references are implicitly dereferenced when you use their name. To put it another way, `typeid` follows references because they're not part of the type system, e.g. you can't have pointer-to-reference-to-int, only pointer-to-int (`int*`) or pointer-to-pointer-to-int (`int **`) – Peter Cordes Jan 08 '23 at 14:15
  • @RichardCritten i dont actually understand "does it to the referred to object" – UPinar Jan 08 '23 at 14:23
  • @PeterCordes understand and will check that. Thank you – UPinar Jan 08 '23 at 14:24
  • 1
    `typeid(refParam).name()` returns the typeid of the referred to object not the reference. – Richard Critten Jan 08 '23 at 14:24
  • @RichardCritten okay understand now, so another question, is there any stl functions to use, when we check the type of `refParam` will return `reference`or `pointer`maybe? anything that has a same space as assembly uses – UPinar Jan 08 '23 at 14:27
  • @RichardCritten when i use `typeid(&refParam).name()` console prints `int * __ptr64` – UPinar Jan 08 '23 at 14:39
  • As it should the code takes the address of the referred to object. Only C++ Standard definition [Object](https://en.cppreference.com/w/cpp/language/object) have a location in memory. References are not objects _"...The following entities are not objects: value, reference,..."_. – Richard Critten Jan 08 '23 at 14:41
  • @RichardCritten yes – UPinar Jan 08 '23 at 14:42
  • @RichardCritten i am a bit confused now. When we check the assembly code it uses 8 byte of memory because references acts like a pointer in ASM, i understand that . But in C++ is `int firstFunction(int& refParam)` this function creating an integer, which has the same memory address of the argument sent to function and because of that it only uses 4 byte space to create that integer? – UPinar Jan 08 '23 at 15:03
  • References __may__ be implemented as pointers. This is an implementation detail and not required by the Standard. References are an alias (like giving your house a name as well as a number). When you have a reference you have 2 (or more) names for the same C++ [Object](https://en.cppreference.com/w/cpp/language/object) – Richard Critten Jan 08 '23 at 15:17
  • @RichardCritten [Memory usage when passing by reference?](https://stackoverflow.com/a/8930513/17755777) that answer also clears – UPinar Jan 08 '23 at 15:46

1 Answers1

6

references are usually implemented as pointers under the hood if it can't be optimized away, and pointers are 8 bytes in 64-bit mode

AspectOfTheNoob
  • 430
  • 1
  • 7
  • 1
    As a function arg, the reference can't be optimized away for the non-inline version. But the spill / reload to the stack *could* be optimized away, the OP just asked it not to be by compiling with optimization disabled on Godbolt. Normally the function would just be `mov eax, [rdi]` / `ret` for the reference version, `mov eax, edi` for the value version, which makes the difference a lot more obvious. – Peter Cordes Jan 08 '23 at 14:27