+ 10
Which is better? Calling a Funtion by value, or calling by reference?
35 Réponses
+ 7
Keep Learning. Keep Coding :)
+ 6
Depends. If the value of the variable passed as argument has to be changed outside the function, use call be reference, otherwise use call by value. Interestingly, Call by reference can be used to return more than one values from a method!
+ 6
Ketan Lalcheta Have a look at the disassembly the compiler produces. https://godbolt.org/z/YxXDvG
Here's the function with pass by value being called:
mov edx, DWORD PTR _y$[ebp]
push edx
mov eax, DWORD PTR _x$[ebp]
push eax
call int sum(int,int) ; sum
and here is the function with the references being called:
lea edx, DWORD PTR _z$[ebp]
push edx
lea eax, DWORD PTR _y$[ebp]
push eax
lea ecx, DWORD PTR _x$[ebp]
push ecx
call void sum2(int &,int &,int &) ; sum2
As you can see, each of the references have to be loaded and pushed onto the stack for the callee, just like the function that uses by value.
+ 6
Ipang Addresses can be dynamic at runtime (thus making the reference arbritary at compile time). In this case what makes the addess dynamic is the fact that the variables are stored on the stack, and thus require using the current stack pointer to calculate its address at runtime.
The second reason it’s arbritrary is because the function is not inlined (in this case due to optimizations being off). Even if the address is static, you still need to push the static address onto the stack for the callee, as any address could be passed to the single instance of that function.
Your last paragraph is correct, except for the last part. Reference copies are always made, regardless of size if thats what you meant. I’m just making the point that the copy size will be the same if variable size is equal to size of a reference. If its greater than the size of the reference, you will have to copy more, which means more CPU instructions will be added. Thats where the advantage of reference comes in.
+ 5
Pass by reference is only better with non-primitive types. The perfomance won't be any different, and can become worse, if you pass primitive types by reference.
Depends on the compiler, passing primitive types by value allows the compiler to do optimizations which is prevented by aliasing. It is cheap, more readable, and safer to develop when working with more people.
+ 5
Ina TYVM for the information provided. I just edited my answer.
Ketan Lalcheta since we were talking primitive types, passing a reference requires a pointer, which is 4 or 8 bytes, more than 1 byte of a char and just equal to 4 byte of an int. IMO, that won't be any better.
+ 4
Nguyễn Văn Hoàng don't you think pass by reference saves object creation and memory utilisation ? reference passed ensures all operation are performed on same variable rather than creating new, performing operation and assigning back new to original one
+ 4
It depends :-p
Call by value when parameters are primitive types (or, possibly, very small objects or structs) and the value is read only within the function (or, modification not visible by the caller)
Call by reference if the parameter is a larger object or structure, or if the value modification must be visible to the caller of the function
If you want to pass a large object but show that it's content should not be modified by the function, consider using a const reference.
+ 4
Ketan Lalcheta In your example it actually is taking up more memory on 64 bit systems, assuming int is 32 bit by default on your compiler. Before the function is called, the arguments are pushed onto the stack or stored in the cpu’s registers depending on the calling convention.
You arent saving on any object creations either because the references have to also be created in order to be passed as parameters.
Furthermore, since you are using a reference, it has to be derefernced each time the CPU reads or writes to it, which means you will have a higher latency whenever you access that variable compared to a local variable stored in a register.
+ 4
aklex thanks for this...Mrityunjay Mani Tripathi appreciate your question as it taught me new thing today...Nguyễn Văn Hoàng too you to as you initiated answer which started changing my thoughts... thanks all
+ 4
Ipang Its not that the original variable is being copied, it’s just that the address of the variable is being copied instead. You can see there’s a slight difference in the assembly, and thats what it is. (LOAD EFFECTIVE ADDRESS instead of MOVE). This is why for any variable less than or equal to the sizeof an of address on your system, you will not save on any copying.
I hope that clears it up a little bit more, and if you have more questions feel free to ask.
+ 4
Ipang The address needs to be copied because the reference can hold the address of any arbitrary variable. The callee doesn’t know which variable it will be getting a reference to, so it needs this information from the caller. So to answer your question, the caller makes the copy.
By sizeof I mean the sizeof the variable type, yes. So essentially if sizeof(int) <= sizeof(void*)
+ 3
Ketan Lalcheta when you pass arguments to void sum, an alias for each argument is created, and memory on stack space will be allocated to hold the alias, which is 4 bytes each on a 32-bit system.
I assume you stated that the references to a and b won't occupy memory because sum is a function and not a class member. Can you explain more about that?
This is a bit beyond my understanding, so I might as well be wrong.
+ 3
Ketan Lalcheta What I mean is that the references themselves are variables aswell when they are used as parameters. When you pass a reference the caller creates an integer and copies the target variable’s address to it, then pushes it onto the stack for callee to use as a reference. In the end it’s practilly the same as copying the original integer and then pushing it onto the stack for the callee.
+ 3
Thanks to everyone who participated in this thread. I never thought a single question can change the way I program.
When I did the 'swapping values' program, the the values of the variable was swapped in call by reference, but not in call by value.
+ 3
aklex It seems I had misunderstood copy variable with copy address, sorry. But then why do the addresses needed to be copied? can't the callee work with the original addresses instead of the copy? and where exactly the copy process takes place? in caller (caller makes copies) or callee scope (callee makes copies)?
I didn't really understand the second paragraph, quoted "This is why for any variable less than or equal to the sizeof an of address on your system, you will not save on copying" do you mean the size of the variable type? like sizeof(int) or is it something else?
+ 3
aklex First of all I want to thank you for being patient enough with my naive curiosity, but I can't help it, until I get a clear understanding of this matter, I won't stop wondering and asking why : )
I still need more information on the reason why copies are needed, as per your explanation the reference can hold an arbitrary address (random) but why is that? isn't it strictly holding the address of the variable it refers to? e.g. "&a" here it is a reference that holds the address of variable "a" right? not some arbitrary address (I'm confused).
And also for the saving part, if I understood you correctly, in 64bit machines an address is 64bit (8 bytes) and it is 32bit (4 bytes) in 32bit machines (disregarding compiler defaults). So this means reference copies will be created anyway (by caller) if we pass any reference holding address of a variable whose type size is less than size of address, I hope I get it right this time ...
Looking forward ...
+ 3
Ketan Lalcheta Thank you, and that code would make an interesting test case, I'll be standing by, look forward to hearing more opinions from senior coders on this matter : )
+ 2
Nguyễn Văn Hoàng please consider this as learning to enhance our knowledge... sole purpose is to gain knowledge...
let's go by example :
int sum (int a , int b) //call by value and return int variable
void sum (int &a, int &b, int& c)// call by reference and c is the one which holds sum
in this scenario, it's not taking more memory... it's just a function not class member... evenif first two argument are pointer, it's not getting occupied like class... only one pointer is required I.e. function pointer to map function with function call (in both cases of function call type, it is required)
but for call as reference, you have saved two int object creation (evenif it's small)..
still you feel one must not go with call by reference for primitive type...? cmiiw anywhere
+ 2
Nguyễn Văn Hoàng yup , you were right... memory will be consumed while declaring variable before function call.. discard that part from last post