21

In a practical environment, using gcc or MS Visual Studio, is it bad to pass the value types which are the same size or less than an int by const reference ?

i.e. is it bad to write such a function:

void f(const bool& b);

or

void f(const char& c);

rather than:

void f(bool b);

or

void f(char c);

The reason I am asking is that I do not see the benefit of passing a reference in these cases but maybe I am missing something.

BlueTrin
  • 9,610
  • 12
  • 49
  • 78
  • 2
    As most people have said, there is not really any point, as passing these by value will probably be faster. However, remember that writing clean code comes before these tiny optimizations, and you may just sometimes have several very similar functions that take arguments by const reference, and then want the `bool` and `char` versions to look consistent. Very minor point, but perhaps worth considering, so you don't get people looking at it thinking "why is this one different?" – BoBTFish Aug 13 '12 at 10:43

6 Answers6

24

It may be slightly bad, or it may not have an effect at all (depends on where the original value is stored, how good the optimizer is, and how it decides to treat your code).

The standard doesn't mandate how references are to be implemented, but in practice compilers implement references using pointers. Therefore in the general case a bool& would be implemented using a bool*, which means that to access the bool you need an extra pointer dereference each time. Since a bool is no bigger than a pointer, there's no reduced memory footprint or less byte copying to offset this drawback.

As a result the accepted practice is to pass primitives around as values since it's more efficient. Of course although passing such around as references won't really blow up anything, and unless you are accessing the value inside a loop will probably not even result in any measurable difference.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • When you write "Since a bool is no bigger than a pointer, there's no reduced memory footprint or less byte copying to offset this drawback.", is a bool actually taking less space than a pointer in practice depending if you pass multiple bools as arguments, leading to actually more memory used by passing by reference or is a bool taking the same space than an int as argument of a function ? – BlueTrin Aug 13 '12 at 11:03
  • The one case where you likely will find primitive types passed by reference (i.e. `bool const&`) is in template instantiations. Unless you explicitly specialize for all primitive types, primitive types and more complex types will use the same signature. – James Kanze Aug 13 '12 at 11:05
  • 4
    @BlueTrin: How much space is taken up depends on the values of `sizeof(bool)` and `sizeof(bool*)` in your architecture. Passing multiples of each parameter does not change the picture. – Jon Aug 13 '12 at 11:32
13

Performance aside, there are actually cases where you will get different behavior.

For instance, passing a const reference makes sure that the function cannot change the value of the referenced variable, but another thread might do so. If you pass by reference (even with const), you will see these changes, if you pass by value, you will not.

Also, the definition of the interface limits what you can do with the variable inside the function. Consider this example:

int foo(int a) {
    a = 5; // valid
}

int bar(const int& a) {
    a = 5; // compiler-error
}

If you pass by reference, and you want to modify the value of the variable for local use, you need to make an extra copy. If you pass by value, you already have a copy.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 5
    Note that you don't need multiple threads for the referenced variable to change. You could have (for example) `bool b(false); void f(const bool& a) {assert(!a); b = true; assert(a);} int main(){f(b);}`. – Mankarse Aug 13 '12 at 11:15
  • 1
    +1 For mentioning possible changes to argument in different places (through other references). It means also that due to possible aliasing problem some optimizations will not be performed. – Tadeusz Kopec for Ukraine Aug 13 '12 at 11:41
2

I think it's better to pass builtin types by value rather then const reference since it's virtually faster. In case of passing by reference you need to create a reference (i.e. take an address) and then dereference when using the variable. In most cases it will be optimized by compiler in any case though

Andrew
  • 24,218
  • 13
  • 61
  • 90
2

One reason would be that you would like to convey to other programmers that the value is constant, it may in some cases be clearer although const bool would suffice.

AndersK
  • 35,813
  • 6
  • 60
  • 86
  • 2
    Passing by value makes it even clearer that the function won't modify the caller's value. – Mike Seymour Aug 13 '12 at 10:51
  • Passing by const-reference does not convey the meaning that the source is constant, only that it will not be modified by the function (see Björn's answer: code outside of the function can still change the value). Additionally, `const bool` as an argument does not convey any information at all, since in a function declaration, the top cv-qualifier is dropped (i.e. `void f( bool );` and `void f( const bool )` are exactly the same function declaration. – David Rodríguez - dribeas Aug 13 '12 at 10:56
0

It really doesn't matter, passing by value makes cleaner code thou and is therefore considered good practice.

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
0

Although in theory it won't be a good idea, as references are usually implemented using pointers. But nevertheless every reasonable compiler should be smart enough to recognize the indifference in semantics between by-const-reference and by-value for fundamental types.

Often you don't have a choice if you have some kind of templated interface that has to work for complex types and fundamental types and you don't want excessive specialization overhead (simplest example: std::vector). But if you have a choice, then passing fundamental types by-value should be preferred.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185