Is it counter-productive to pass primitive types by reference? [duplicate]

Possible Duplicate:
Is it better to pass by value or by reference for basic datatypes?
Reasons to not pass simple types by reference?

I did some testing where I had two scenarios, each with two identical functions- one passing the parameter by reference and the other by value. The scenario with strings showed a massive performance increase (because a copy of string is made, calling a constructor) whereas the test with long didn't show any performance increase when passing the value by reference. In fact, sometimes the performance was worse.

Is this expected with primitive types? Is there no point passing them by reference?

I was expecting a copy of a primitive type is made when not using by reference and therefore expected a small performance-boost.


Solution 1:

You get the best performance from passing primitive types by value. This is because:

  • primitives are blitable, so the cost of the copy depends on the size
  • primitives are small, only double and long long are bigger than a reference in most environments
  • pass-by-value avoids aliasing, allowing the optimizer to really do its thing

This last point is often overlooked but can make a considerable difference.

Solution 2:

Yes, that's the expected behavior. When you're passing parameters by reference, you're actually passing an address of the variable (like with pointer). Usually address is a 4 or 8-byte integer, so unless your primitive type is larger than that, you won't gain any performance improvement (and even if it's larger, you probably won't)

Solution 3:

Modern compilers are pretty clever, so if the function isn't "hidden" (that is, part of something the compiler can't see at the time of producing the code), it may well make no difference at all. HOwever, if it the compiler follows your instructions, passing simple types as reference does potentially make a big difference. Particularly if the value is updated many times in the code.

I saw some code where I worked, which did something like this:

void SomeClass::FindLength(int &len)
{
     listEntry* list = theList;   // theList is a member variable. 
     len = 0;
     while (list)
     {
         len++;
         list = list->next;
     }
 }

By alterning the code to do:

void SomeClass::FindLength(int &len)
{
     listEntry* list = theList;   // theList is a member variable. 
     int tempLen = 0;
     while (list)
     {
         tempLen++;
         list = list->next;
     }
     len = tempLen;
 }

the whole code ran some 30% faster, and called from a lot of places (and I think there was some if-condition in the middle, so we couldn't just keep track of the length). And since it was part of an API function, it wasn't possible to change the function signature.

The reason it was slower using the reference is that the compiler would write to the reference value EVERY time it was updated, which was a load from memory to register, increment register and a store register to memory. With the tempLen solution, the compiler could use a register, which is much faster.