Passing integers as constant references versus copying

C++

C++ Problem Overview


This might be a stupid question, but I notice that in a good number of APIs, a lot of method signatures that take integer parameters that aren't intended to be modified look like:

void method(int x);

rather than:

void method(const int &x);

To me, it looks like both of these would function exactly the same. (EDIT: apparently not in some cases, see answer by R Samuel Klatchko) In the former, the value is copied and thus can't change the original. In the latter, a constant reference is passed, so the original can't be changed.

What I want to know is why one over the other - is it because the performance is basically the same or even better with the former? e.g. passing a 16-bit value or 32-bit value rather than a 32-bit or 64-bit address? This was the only logical reason I could think of, I just want to know if this is correct, and if not, why and when one should prefer int x over const int &x and vice versa.

C++ Solutions


Solution 1 - C++

It's not just the cost of passing a pointer (that's essentially what a reference is), but also the de-referencing in the called method's body to retrieve the underlying value.

That's why passing an int by value will be virtually guaranteed to be faster (Also, the compiler can optimize and simply pass the int via processor registers, eliminating the need to push it onto the stack).

Solution 2 - C++

To me, it looks like both of these would function exactly the same.

It depends on exactly what the reference is to. Here is an admittedly made up example that would change based on whether you pass a reference or a value:

static int global_value = 0;

int doit(int x)
{
    ++global_value;
    return x + 1;
}

int main()
{
    return doit(global_value);
}

This code will behave differently depending on whether you have int doit(int) or int doit(const int &)

Solution 3 - C++

Integers are usually the size of the processor's native word and can pass easily into a registers. From this perspective, there is no difference between passing by value or passing by constant reference.

When in doubt, print the assembly language listing for your functions to find out how the compiler is passing the argument. Print out for both pass by value and pass by constant reference.

Also, when passing by value, the function can modify the copy. When passing by constant reference, the function cannot modify the variable (it's marked as const).

Solution 4 - C++

There will probably be a very, very small de-optimization for passing by reference, since at the very least one dereference will need to occur to get the actual value (unless the call is inlined, the compiler cannot simply pass the value due to the fact that the call site and function might be separately compiled, and it's valid and well-defined to cast away the const for a passed parameter that isn't actually const itself - see https://stackoverflow.com/questions/1727569/what-are-the-benefits-to-passing-integral-types-by-const-ref/1727606#1727606). Note, however, that the 'de-optimization' is likely to be so small as to be difficult to measure.

Most people seem to dislike pass-by-const-ref for built-ins because of this (some very much). However, I think that it it might be preferable in some cases if you want the compiler to assist you in ensuring that the value isn't accidentally changed within the function. It's not a big thing, but sometimes it might help.

Solution 5 - C++

  • Depending on the underlying instruction set, an integer parameter can be passed as register or on the stack. Register is definitely faster than memory access, which would always be required in case of const refs (considering early cache-less architectures)

  • You cannot pass an int literal as a const int&

  • Explicit type-casts allow you cast a const int& into * (const int *) opening the possibility to change the value of the passed reference

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJake PetroulesView Question on Stackoverflow
Solution 1 - C++Tony the PonyView Answer on Stackoverflow
Solution 2 - C++R Samuel KlatchkoView Answer on Stackoverflow
Solution 3 - C++Thomas MatthewsView Answer on Stackoverflow
Solution 4 - C++Michael BurrView Answer on Stackoverflow
Solution 5 - C++devioView Answer on Stackoverflow