31

To avoid the inefficiency of copy-by-value when calling a function (say, "fillRect"), I want to pass the parameters by reference.

If I supply the parameters as declared local variables, it works fine. But if I supply any as "literal" integers, I get a compile error (no matching function).

void fillRect( int &x, int &y, int &width, int &height )
{
    // do something
}

int x=10, y=20, w=100, h=80;

fillRect(x, y, w, h); // this compiles and works!
fillRect(x, y, 100, 80); // but this doesn't compile ... why?

What gives?


(Forgive my naivety: I'm pretty new to C++.)

As many people have pointed out, pass-by-reference isn't generally appropriate as an optimisation for primitive types. This is excellent to know, so thank you all! Even so, my question was really more about why literal values can't seem be passed by reference, which has been addressed by the accepted answer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aaaidan
  • 7,093
  • 8
  • 66
  • 102
  • 9
    There are no references in C, that's C++ – K-ballo Oct 09 '11 at 03:20
  • 8
    Pass by value is actually *more* efficient than pass by reference in the case of `int`s (on most sane architectures). – Mankarse Oct 09 '11 at 03:21
  • 2
    @Mankarse, that's not 100% correct--the compiler does have some discretion in implementing the reference, and so passing a primitive by value isn't necessarily *more* efficient. It's probably more correct to say that passing an int by value is never *less* efficient. Unless your compiler is buggy. :-) – Ian Ni-Lewis Sep 30 '15 at 13:51

4 Answers4

33

You cannot bind a literal to an lvalue reference to non-const (because modifying the value of a literal is not an operation that makes sense). You can however bind a literal to a reference to const.

So this will compile if you declare fillRect as:

void fillRect(int const& x, int const& y, int const& width, int const& height)

In this case you are passing ints. ints are so cheap to copy that passing by them by reference will probably make the performance of your program worse.

The function fillRect is probably so expensive that the cost of passing its arguments is totally irrelevant in any case. Or maybe it will be inlined, and there will be no cost whatsoever to passing the arguments. These sorts of micro-optimisations are usually not optimisations at all, and should always be guided by the results of profiling (if they are done at all).

Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • 1
    Note that this is now not entirely correct, as in C++11 and later, you can bind a literal to a non-const rvalue reference. – Mankarse Jan 06 '17 at 02:55
  • This is definitely the best answer because, not only is it the only one that actually answers the question, but it also very politely hints that passing by value is probably preferable anyway in this case. – ThisGuyCantEven Sep 18 '21 at 15:14
31

To avoid the inefficiency of copy-by-value when calling a function

Stop right there.

Passing by reference does not necessarily mean "fast". This goes doubly so for basic types. Indeed, accessing basic types by reference will be slower than doing so by value. A reference is not magic. It's generally implemented as a pointer. So every time you access that value, you are likely doing a pointer dereference.

This sounds like some kind of micro-optimization. Do not optimize without profiling. Unless you have really good reason to expect the performance of your application to hinge on value vs. reference parameters, just do what makes sense.

You should only pass basic types by reference if you intend to modify them.

dragonroot
  • 5,653
  • 3
  • 38
  • 63
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    -1 because this answer (a) makes somewhat derogatory assumptions about the OP's expertise, and (b) doesn't answer the question. As a warning to the unwary, it has value, but probably should be posted as a comment rather than an answer. – Ian Ni-Lewis Sep 30 '15 at 13:38
  • 4
    @IanNi-Lewis I see what you're saying about the tone of this answer, but OP actually found this helpful enough to upvote. The assuptions about OP's expertise were warranted, as the question title ends with "(Newbie)". I think in this case, I was asking the wrong question, and these answers have been right to redirect it. – aaaidan Oct 01 '15 at 21:04
  • I'm by no means an expert, but why do all of these answers assume that the only reason to pass by reference is for computational performance? Isn't this more often used to reduce the memory footprint of the stack by having less copies of the same value? That being said, 4 additional `int` in a frame is negligible and probably not worth the computational overhead of passing by reference in this case. – ThisGuyCantEven Sep 18 '21 at 15:10
  • 4
    @ThisGuyCantEven on a system with 64-bit pointers, passing by reference could easily take *more* stack space than passing an int by value! And that observation applies to the speed argument as well. – Mark Ransom Sep 18 '21 at 17:44
  • @MarkRansom thanks that concisely and precisely answers my question. – ThisGuyCantEven Sep 20 '21 at 02:25
12

Passing by reference is actually slower for such small values. To pass by reference, it is, under-the-hood, passing a pointer (which is an int-sized value anyway). Then, there is a hidden extra pointer indirection that is not free. It is more direct to simply pass the value.

Do this:

void fillRect( int x, int y, int width, int height )
{
    // do something
}

The compiler will most likely inline your function anyway, unless its big. So you wouldn't have been able to improve the performance by being "clever" in how you declared the function.

VoidStar
  • 5,241
  • 1
  • 31
  • 45
5

First you should take heed of the other's advice to prefer passing by value for simple types. C (and by extension C++) were designed with this use case in mind, and that's what they're optimized for.

Second you should always use a const reference unless you intend to modify the variable. A literal can be bound to a const reference but not a non-const one.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622