Reputation: 1711
void DoWork(int n);
void DoWork(const int &n);
What's the difference?
Upvotes: 150
Views: 263423
Reputation: 879
There are three methods you can pass values to functions:
Pass by value:
void f(int n) {
n = n + 10;
}
int main() {
int x = 3;
f(x);
cout << x << endl;
}
Output: 3
.
Disadvantage: When parameter x
is passed through the f
function, the compiler creates a copy in memory of x
. So, wastage of memory.
Pass by reference:
void f(int& n) {
n = n + 10;
}
int main() {
int x = 3;
f(x);
cout << x << endl;
}
Output: 13
.
It eliminates pass by value disadvantage, but if the programmer does not want to change the value, then use const
reference.
Constant reference:
void f(const int& n) {
n = n + 10; // Error: assignment of read-only reference ‘n’
}
int main() {
int x = 3;
f(x);
cout << x << endl;
}
Output: Throws an error at n = n + 10
because when we pass the const
reference parameter argument, it is a read-only parameter; you cannot change the value of n
.
Upvotes: 61
Reputation: 1
Upvotes: 0
Reputation: 11
Also, you can use the const int& x
to initialize it with r-value and this will cause that you can't change x or bind it with another values.
const int& x = 5; // x is a constant reference to r-value 5
x = 7; // expression is not a modifable value
Upvotes: 0
Reputation: 7876
The difference is more prominent when you are passing a big struct/class:
struct MyData {
int a,b,c,d,e,f,g,h;
long array[1234];
};
void DoWork(MyData md);
void DoWork(const MyData& md);
When you use use 'normal' parameter, you pass the parameter by value and hence creating a copy of the parameter you pass. If you are using const reference, you pass it by reference and the original data is not copied.
In both cases, the original data cannot be modified from inside the function.
EDIT:
In certain cases, the original data might be able to get modified as pointed out by Charles Bailey in his answer.
Upvotes: 131
Reputation: 791361
The important difference is that when passing by const
reference, no new object is created. In the function body, the parameter is effectively an alias for the object passed in.
Because the reference is a const
reference the function body cannot directly change the value of that object. This has a similar property to passing by value where the function body also cannot change the value of the object that was passed in, in this case because the parameter is a copy.
There are crucial differences. If the parameter is a const
reference, but the object passed it was not in fact const
then the value of the object may be changed during the function call itself.
E.g.
int a;
void DoWork(const int &n)
{
a = n * 2; // If n was a reference to a, n will have been doubled
f(); // Might change the value of whatever n refers to
}
int main()
{
DoWork(a);
}
Also if the object passed in was not actually const
then the function could (even if it is ill advised) change its value with a cast.
e.g.
void DoWork(const int &n)
{
const_cast<int&>(n) = 22;
}
This would cause undefined behaviour if the object passed in was actually const
.
When the parameter is passed by const reference, extra costs include dereferencing, worse object locality, fewer opportunities for compile optimizing.
When the parameter is passed by value an extra cost is the need to create a parameter copy. Typically this is only of concern when the object type is large.
Upvotes: 157
Reputation: 25487
Firstly, there is no concept of cv-qualified references. So the terminology 'const reference' is not correct and is usually used to describle 'reference to const'. It is better to start talking about what is meant.
$8.3.2/1- "Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef (7.1.3) or of a template type argument (14.3), in which case the cv-qualifiers are ignored."
Here are the differences
$13.1 - "Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations.112). In particular, for any type T, “pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.”
void f(int &n){
cout << 1;
n++;
}
void f(int const &n){
cout << 2;
//n++; // Error!, Non modifiable lvalue
}
int main(){
int x = 2;
f(x); // Calls overload 1, after the call x is 3
f(2); // Calls overload 2
f(2.2); // Calls overload 2, a temporary of double is created $8.5/3
}
Upvotes: 1
Reputation: 3825
Since none of you mentioned nothing about the const keyword...
The const keyword modifies the type of a type declaration or the type of a function parameter, preventing the value from varying. (Source: MS)
In other words: passing a parameter by reference exposes it to modification by the callee. Using the const keyword prevents the modification.
Upvotes: 7
Reputation: 20142
With
void DoWork(int n);
n
is a copy of the value of the actual parameter, and it is legal to change the value of n
within the function. With
void DoWork(const int &n);
n
is a reference to the actual parameter, and it is not legal to change its value.
Upvotes: 11
Reputation: 52519
The first method passes n
by value, i.e. a copy of n
is sent to the function. The second one passes n
by reference which basically means that a pointer to the n
with which the function is called is sent to the function.
For integral types like int
it doesn't make much sense to pass as a const reference since the size of the reference is usually the same as the size of the reference (the pointer). In the cases where making a copy is expensive it's usually best to pass by const reference.
Upvotes: 1