Passing by value, by pointer-to-const, and by const-reference all prevent the caller's actual
parameter from being changed by the function. Passing by pointer (to non-const) and by
(non-const) reference allows the function to change the caller's actual parameter.
Passing by value makes a
copy of the caller's actual parameter onto the stack.
References are typically implemented in the compiler as pointers, so passing by reference
and by pointer both store a pointer onto the stack, which is very cheap.
From a performance perspective, pointers and references are equivalent. However, pointers
can be NULL whereas references cannot. A well-implemented function that takes a pointer as
parameter must check the pointer for NULL before dereferencing, and then deal with the
possibility of NULL (often times, but not always, an error case). A well-implemented function
that takes a reference as parameter need not check the reference for NULL since it cannot be,
so the error case is avoided. But accessing the data "referred to" by a pointer or a reference
requires one extra memory access than if passed by value.
From an implementation perspective, accessing the data "referred to" by the pointer requires
the dereference operator (*). Accessin the data "referred to" by a reference is the same as
if the parameter were passed by value. Examples, to illustrate:
1 2 3
|
int by_value( int x ) { return x + 5; }
int by_pointer( const int* x ) { return x == NULL ? 0 : *x + 5; } // Returns 0 if x == NULL or *x == -5...
int by_reference( const int& x ) { return x + 5; } // Same as by_value case!
|
In general, pass by value for easy-to-copy types and you don't need to change the caller's
actual parameter. If you don't need to change the caller's actual parameter but it is expensive
to copy onto the stack, use const references. If you do need to change the caller's actual
parameter, use a non-const reference. You should use pointers only when NULL is not an
error case for your function.