4

I've always heard that a good practice to ensure best performance was to:

  • pass fundamental types (int, double...) by value
  • pass classes by const reference

Nowadays, using C++11 and full optimizations under a compiler, is there an overhead when one passes a fundamental type by const reference?

And furthermore, when T is int will the following function:

template <typename T> inline void f(const T& x);

be slower than:

template <typename T> inline void f(const T x);
Vincent
  • 57,703
  • 61
  • 205
  • 388
  • 1
    If they are really inlined, no, the compiler will optimize both to the same code. – David Rodríguez - dribeas Jul 22 '13 at 04:35
  • 1
    See also http://stackoverflow.com/a/17710439/341970 – Ali Jul 22 '13 at 08:12
  • And this is a good one: [Why does changing `const ull` to `const ull&` in function parameter result in performance gain?](http://stackoverflow.com/q/14805641/341970) So I wouldn't sweat it unless the profiler says otherwise. – Ali Jul 22 '13 at 08:20

1 Answers1

6

If the compiler is really inlining the code (which is common for simple templates) there will be no difference. The problem becomes apparent when the function cannot be inlined, and the out-of-line definition is called.

In that case, passing a reference can involve an extra dereference when accessing the variable (at the very least the first time, possibly multiple times) At the same time, the compiler can perform more aggressive optimizations if the argument is by value, since it knows that the variable cannot be accessed/modified outside of the current function.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • @David Rodríguez - dribea Funny this question comes up again. I am still away so I cannot get back to our discussion on this topic. – Ali Jul 22 '13 at 08:15
  • @DavidRodríguez-dribeas: They are semantically different, so no, they cannot always be optimized to the same code. – newacct Jul 22 '13 at 09:34
  • @newacct: In a program without undefined behavior, if the function is inlined and the object is not modified locally (which is the case given the signature) the code will be injected into the scope of the caller and the compiler will remove the reference (which is semantically just an alias for the other name) – David Rodríguez - dribeas Jul 22 '13 at 12:46
  • @DavidRodríguez-dribeas: Consider `int foo; template inline void f(const T& x) { foo = 2; std::cout << x; } int main() { foo = 1; f(foo); return 0; } ` It outputs 2. But when the `&` is removed, it outputs 1. – newacct Jul 23 '13 at 02:14
  • @newacct: You are not considering a piece of code that can be used equivalently. You built an example where the semantics are completely different and thus there is no option. The question is about potential difference of performance in code where you can *decide* which of the two signatures to use (they behave equivalently). If you understood from the question that you can freely change one for the other, that was not the intention. The intention is that when they are equivalent and the function is inlined, the compiler will most likely generate the same code. – David Rodríguez - dribeas Jul 23 '13 at 02:46
  • @DavidRodríguez-dribeas: but how can the compiler know whether it would be equivalent when you remove the `&` or not? Because the compiler cannot know in general, in the non-reference case, when inlined, it must keep a copy of the parameter that is distinct from the original variable; whereas in the reference case it can just use the original variable. – newacct Jul 23 '13 at 06:54