0

I came across a Leetcode practice where an input argument to a function is vector<int>& nums. I normally use C, so I rarely come across this format before. I also just realized that the reference method does not work in C but only in C++ based on testing this code in onlinegdb.com. What are the other differences between how these two functions operate?

Function using pointers:

void FirstModifier(int *a, int *b)
{
    /* In the event that a and b are too large to copy to stack,
       use pointers (instead of pass by value). Supported in 
       C and C++. */
    (*a)++;
    (*b)++;
}

Function using references (from this forum):

void SecondModifier(int& a, int& b)
{
    /* If a and b are too large to copy to stack,
       use pass by reference (instead of pass by value). Use 
       const to prevent modifying variables. This method is
       only supported in C++, not C. */
    a++;
    b++;
}

Do they both work the same way? Assuming that a pointer and a reference both consume 4 bytes on a 32-bit machine, do both methods use the same amount of stack as soon as code enters the function? What are some reasons why the second method would be preferred over the first method?

Are the other notable differences in syntax? If I use the first method, I have to call it in this way: FirstModifier(&FirstVar, &SecondVar), while the second method can be called with SecondModifier(FirstVar, SecondVar). Inside the first function, I would also have to use (*a) to retrieve contents of the first variable, while in the second function, I can simply use a to access its value.

Enzo Ferber
  • 3,029
  • 1
  • 14
  • 24
Cimory
  • 82
  • 1
  • 8
  • https://www.geeksforgeeks.org/pointers-vs-references-cpp/ – Vlad Feinstein Aug 10 '21 at 18:58
  • One different that I can point out is that when you use pointers as parameters, it creates its own space. Since you declared 2 integer pointers the size of that function would be sizeof(a) * 2. However references are just aliases. I use pointers when I need to pass iterators or I know that I would require some operations. I use references when I need to do some basic operations, printing, and use const ref & if I need to pass literal arguments. – Programming Rage Aug 10 '21 at 18:58
  • `int& a` is analogous (but not identical) to `int *a`, but it is very different from `vector& a`. The forms with `&` are C++-only. – John Bollinger Aug 10 '21 at 19:00
  • This should be of use: https://stackoverflow.com/q/388242/2079303 – eerorika Aug 10 '21 at 19:01
  • 1
    @ProgrammingRage, it is a little disingenuous to say that references are just aliases. At least when they appear as arguments to a function that is not inlined, they are often implemented via pointers. – John Bollinger Aug 10 '21 at 19:03
  • @JohnBollinger Could you elaborate more on "they are generally implemented via pointers?" Do you refer to this: `int *x = &i`? – Programming Rage Aug 10 '21 at 19:06
  • 5
    @ProgrammingRage At the asm level, `int f(int*)` has identical code to `int f(int&)`. A member reference usually has the same size and alignment requirements as a pointer – Artyer Aug 10 '21 at 19:08
  • ^^^ I mean this. ^^^ – John Bollinger Aug 10 '21 at 19:09
  • @ProgrammingRage So if I were to use the second method on a microcontroller, the function would not even use the stack on SRAM even in a function call? My understanding is that the first method would allocate 4-bytes in the stack to store the address, and if any changes were made, the processor would use something like `LDR` to retrieve the value stored in that address, increment it in the internal register, and store the updated value back to wherever it is located. I assumed that the second method would be the same. – Cimory Aug 10 '21 at 19:11
  • In principle, copy-in / copy-out could be used instead in some cases, but in practice, it's easier to always use pointers than to try to establish rules for when copy-in / copy-out should be used instead. And interoperability requires clear, consistently applied rules about that. – John Bollinger Aug 10 '21 at 19:12
  • @JohnBollinger Could you elaborate why `int& a` is very different from `vector& a`? – Cimory Aug 10 '21 at 19:12
  • @Cimory because `int`s are very different from `vector`s, the element type of the vector notwithstanding. The distinction between `int` and `int[1]` is much less. – John Bollinger Aug 10 '21 at 19:14
  • A pointer type is a distinct object type that requires some amount of storage. You can have arrays of pointers, pointers to pointers, references to pointers, etc. A reference type need not have any storage (that's left unspecified). You *cannot* have arrays of references, pointers to references, or references to references. You can do arithmetic on pointers and use the `++` and `--` operators on them, whereas you can't do that with references. A pointer can point to any object of the correct type - a reference only ever refers to a specific object. – John Bode Aug 10 '21 at 19:15
  • 1
    Put another way, a pointer can exist independently of any pointed-to object, whereas a reference cannot. – John Bode Aug 10 '21 at 19:19
  • @JohnBollinger Even though `int` and `vector` are different (size-wise due to number of elements, constructors, class members), would `int& a` and `vector& a` operate in a similar manner in the assembly level? They would still be similar in how they use registers, stack, etc.? Also, when you mentioned copy-in/copy-out, did you mean using `func(int a, int b)` instead of pointers/references? – Cimory Aug 10 '21 at 19:21
  • @JohnBode I think I'm starting to understand. So the compiler will remember what a reference references to, so it's more similar to a compiler replacing preprocessor values throughout the code. Is that analogy correct? Why would a reference not consume the stack inside a function call though? – Cimory Aug 10 '21 at 19:24
  • @Cimory: JohnBode has learned a particular simplified way of thinking about references that is neither complete nor an accurate description of the C++ language rules. Your question shows you are already well beyond that simplified level of understanding. – Ben Voigt Aug 10 '21 at 19:44
  • 1
    @JohnBode: Good compilers perform aliasing analysis on pointers and references equally well, and will not reserve storage unnecessarily for either one (such as parameters of a function being inlined). References actually bind to storage locations, not objects. References can be left dangling after the bound storage location is deallocated. References can be bound to a storage location where an object will someday exist, before the object is created. – Ben Voigt Aug 10 '21 at 19:48
  • @BenVoigt - I'm using "object" in the C sense (a region of storage that can hold a value), not in the "instance of a class" sense. – John Bode Aug 10 '21 at 19:52
  • @JohnBode: It doesn't make any sense to use the C meaning in a C++ question. The C++ standard contains a definition for the word "object", that's the meaning that word has when talking about C++. https://eel.is/c++draft/intro.object – Ben Voigt Aug 10 '21 at 19:54
  • @BenVoigt Thanks for the explanation! I guess it is safe to assume that pointers and references as input arguments in a function/routine will most likely use the same amount of memory/stack. @Artyer also mentioned that `int f(int*)` and `int f(int&)` have identical codes at the assembly level, so it is safe to assume that the two methods in the question does not have significant difference in performance/runtime. – Cimory Aug 10 '21 at 20:42

0 Answers0