2011-10-14

Floating-point reference parameters in C++

Today I had some time to verify an idea I have always had: in C++ it is better to avoid unnecessary references when passing double arguments to functions.

The idea to verify this came while I was inspecting some C++ code. One of the functions had a parameter which was declared as double & despite the fact that such parameter was never changed in the function body. Consider this example:

double
doubleThis(double & x)
{
return x * 2;
}

The problem with the double & lies in the fact that the function receives a pointer to double instead of a double: therefore it has to look for the value pointed by the argument and copy it into a floating-point register:

__Z24doubleThisRd:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movsd (%rax), %xmm0 # Put in xmm0 the value pointed by RAX
addsd %xmm0, %xmm0 # Calculate x+x instead of 2x
leave
ret

Had we defined doubleThis with a double parameter (without the & indicating a reference) like this:

double
doubleThis(double x)
{
return x * 2;
}
view raw double.cpp hosted with ❤ by GitHub

then GCC would have produced the following assembly code:

__Z11doubleThisd:
pushq %rbp
movq %rsp, %rbp
movsd %xmm0, -8(%rbp)
movsd -8(%rbp), %xmm0 # Directly copy the parameter into the FP register
addsd %xmm0, %xmm0 # Calculate x+x instead of 2x
leave
ret
view raw double.s hosted with ❤ by GitHub

which is shorter and faster.

In short: avoid using unnecessary references. Apart from the fact that they obfuscate the meaning of the function (a reference parameter indicates that the function is going to alter its contents, while this is not true for doubleThis), depending on the type of the parameter they might also produce slower code.