Does const call by reference improve performance when applied to primitive types?
Asked Answered
A

5

10

Concerning objects (especially strings), call by reference is faster than call-by-value because the function call does not need to create a copy of the original object. Using const, one can also ensure that the reference is not abused.

My question is whether const call-by-reference is also faster if using primitive types, like bool, int or double.

void doSomething(const string & strInput, unsigned int iMode);
void doSomething(const string & strInput, const unsigned int & iMode);

My suspicion is that it is advantageous to use call-by-reference as soon as the primitive type's size in bytes exceeds the size of the address value. Even if the difference is small, I'd like to take the advantage because I call some of these functions quite often.

Additional question: Does inlining have an influence on the answer to my question?

Abrahan answered 19/3, 2015 at 10:7 Comment(2)
Most of the time there should be no effect. But profiling for a particular case would be good. I pass primitive types by values and objects by const reference. Inlining should not change any thing.Tabret
It's important to understand that they're not the same thing (ref. https://mcmap.net/q/260143/-int-vs-const-int-amp-closed eg.). Choose the one that matches your needs - if passing by value is sufficient, then do that - if passing by reference is required, then do that.Mealy
G
10

My suspicion is that it is advantageous to use call-by-reference as soon as the primitive type's size in bytes exceeds the size of the address value. Even if the difference is small, I'd like to take the advantage because I call some of these functions quite often.

Performance tweaking based on hunches works about 0% of the time in C++ (that's is a gut feeling I have about statistics, it works usually...)

It is correct that the const T& will be smaller than the T if sizeof(T) > sizeof(ptr), so usually 32-bits, or 64, depending on the system..

Now ask yourself :

1) How many built-in types are bigger than 64 bits ?

2) Is not copying 32-bits worth making the code less clear ? If your function becomes significantly faster because you didn't copy a 32bit value to it, maybe it doesn't do much ?

3) Are you really that clever ? (spoiler alert : no.) See this great answer for the reason why it is almost always a bad idea : https://mcmap.net/q/260143/-int-vs-const-int-amp-closed

Ultimately just pass by value. If after (thorough) profiling you identify that some function is a bottleneck, and all of the other optimizations that you tried weren't enough (and you should try most of them before this), pass-by-const-reference.

Then See that it doesn't change anything. roll-over and cry.

Girardi answered 19/3, 2015 at 10:43 Comment(0)
L
5

I addition to the other answers I would like to note that when you pass a reference and use (aka dereference) that a lot in your function, it could be slower than making a copy.

This is because local variables to a function (usually) get loaded into the cache together, but when one of them is a pointer/reference and the function uses that, it could result in a cache miss. Meaning it needs to go to the (slower) main memory to get the pointed to variable, which could be slower than making the copy which is loaded in cache together with the function.

So even for 'small objects' it could be potentially faster to just pass by value.

(I read this in the very good book: Computer Systems: a programmers perspective)

Some more interesting discussion on the whole cache hit/miss topic: How does one write code that best utilizes the CPU cache to improve performance?

Linnie answered 19/3, 2015 at 10:58 Comment(0)
Y
4

On a 64-bit architecture, there is no primitive type---at least not in C++11---which is larger than a pointer/reference. You should test this, but intuitively, there should be the same amount of data shuffled around for a const T& as for an int64_t, and less for any primitive where sizeof(T) < sizeof(int64_t). Therefore, insofar as you can measure any difference, passing primitives by value should be faster if your compiler is doing the obvious thing---which is why I stress that if you need certainty here, you should write a test case.

Another consideration is that primitive function parameters can end up in CPU registers, which makes accessing them as fast as a memory access can be. You might find there are more instructions being generated for your const T& parameters than for your T parameters when T is a primitive. You could test this by checking the assembler output by your compiler.

Yacano answered 19/3, 2015 at 10:43 Comment(0)
P
2

I was taught:

  • Pass by value when an argument variable is one of the fundamental built-in types, such as bool, int, or float. Objects of these types are so small that passing by reference doesn't result in any gain in efficiency. Also if you want to make a copy of a variable.

  • Pass a constant reference when you want to efficiently pass a value that you don't need to change.

  • Pass a reference only when you want to alter the value of the argument variable. But to try to avoid changing argument variables whenever possible.

Pipkin answered 19/3, 2015 at 10:33 Comment(0)
B
2

const is a keyword which is evaluated at compiletime. It does not have any impact on runtime performance. You can read some more about this here: https://isocpp.org/wiki/faq/const-correctness

Beechnut answered 19/3, 2015 at 10:41 Comment(1)
const cannot have a negative impact on performance as its a purely compile time thing. However it may still have a positive effect with smart compilers.Bianchi

© 2022 - 2024 — McMap. All rights reserved.