Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing constant references of primitive types as function arguments

Consider the following function:

template <class T, class Priority>
void MutableQueue<T, Priority>::update(const T& item, const Priority& priority)
{
   ...
}

Would modern x86-64 compilers be smart enough to pass the priority argument by value rather than reference if the priority type could fit within a register?

like image 761
Jansen du Plessis Avatar asked May 02 '15 17:05

Jansen du Plessis


People also ask

Can constants be passed by reference?

Passing by const reference is the preferred way to pass around objects as a smart alternative to pass-by-value.

How do you pass the reference of a variable in a function as parameter?

Pass-by-reference means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the argument by using its reference passed in. The following example shows how arguments are passed by reference.

How are the primitive data types passed?

Passing primitive types in function: Primitive types are always passed by value. These are immutable. This means that even if we change the value in the function, the original value will not change. There are a total of five primitive data types in JavaScript.

What are the benefits of pass by reference method of parameter passing?

If you recall, using pass by reference allows us to effectively “pass” the reference of a variable in the calling function to whatever is in the function being called. The called function gets the ability to modify the value of the argument by passing in its reference.


2 Answers

Compiler may do the optimization, but it is not mandatory.

To force to pass the "best" type, you may use boost: http://www.boost.org/doc/libs/1_55_0/libs/utility/call_traits.htm

Replacing const T& (where passing by value is correct) by call_traits<T>::param_type.

So your code may become:

template <class T, class Priority>
void MutableQueue<T, Priority>::update(call_traits<T>::param_type item,
                                       call_traits<Priority>::param_type priority)
{
   ...
}
like image 100
Jarod42 Avatar answered Oct 06 '22 01:10

Jarod42


As @black mentioned, optimizations are compiler and platform dependent. That said, we typically expect a number of optimizations to happen day-to-day when using a good optimizing compiler. For instance, we count on function inlining, register allocation, converting constant multiplications and divisions to bit-shifts when possible, etc.

To answer your question

Would modern x86-64 compilers be smart enough to pass the priority argument by value rather than reference if the priority type could fit within a register?

I'll simply try it out. See for your self:

  • GCC latest (without inlining)
  • CLANG 3.5.1 (without inlining)

This is the code:

template<typename T>
T square(const T& num) {
   return num * num;
}

int sq(int x) {
  return square(x);
}

GCC -O3, -O2, and -O1 reliably perform this optimization.

Clang 3.5.1, on the other hand, does not seem to perform this optimization.

Should you count on such optimization happening? Not always, and not absolutely--the C++ standard says nothing about when an optimization like this could take place. In practice, if you are using GCC, you can 'expect' the optimization to take place.

If you absolutely positively want to ensure that such optimization happens, you will want to use template specialization.

like image 43
EyasSH Avatar answered Oct 06 '22 00:10

EyasSH