Pass by reference
When passing arguments by value, the only way to return a value back to the caller is via the function’s return value. While this is suitable in many cases, there are a few cases where better options are available. One such case is when writing a function that needs to modify the values of an array (eg. sorting an array). In this case, it is more efficient and more clear to have the function modify the actual array passed to it, rather than trying to return something back to the caller.
One way to allow functions to modify the value of argument is by using pass by reference. In pass by reference, we declare the function parameters as references rather than normal variables:
void AddOne(int &y) // y is a reference variable
{
y = y + 1;
}
When the function is called, y will become a reference to the argument. Since a reference to a variable is treated exactly the same as the variable itself, any changes made to the reference are passed through to the argument!
The following example shows this in action:
void foo(int &y) // y is now a reference
{
using namespace std;
cout << "y = " << y << endl;
y = 6;
cout << "y = " << y << endl;
} // y is destroyed here
int main()
{
int x = 5;
cout << "x = " << x << endl;
foo(x);
cout << "x = " << x << endl;
return 0;
}
This program is the same as the one we used for the pass by value example, except foo’s parameter is now a reference instead of a normal variable. When we call foo(x), y becomes a reference to x. This snippet produces the output:
x = 5 y = 5 y = 6 x = 6
Note that the value of x was changed by the function!
Here is another example:
void AddOne(int &y)
{
y++;
}
int main()
{
int x = 5;
cout << "x = " << x << endl;
AddOne(x);
cout << "x = " << x << endl;
return 0;
}
This example prints:
x = 5; x = 6;
As you can see, the function was able to change the value of the argument.
Sometimes we need a function to return multiple values. However, functions can only have one return value. One way to return multiple values is using reference parameters:
#include <math.h> // for sin() and cos()
void GetSinCos(double dX, double &dSin, double &dCos)
{
dSin = sin(dX);
dCos = cos(dX);
}
This function takes one parameter (by value) as input, and “returns” two parameters (by reference) as output.
Pass by const reference
One of the major disadvantages of pass by value is that all arguments passed by value are copied to the parameters. When the arguments are large structs or classes, this can take a lot of time. References provide a way to avoid this penalty. When an argument is passed by reference, a reference is created to the actual argument (which takes minimal time) and no copying of values takes place. This allows us to pass large stucts and classes with a minimum performance penalty.
However, this also opens us up to potential trouble. References allow the function to change the value of the argument, which in many cases is undesirable. If we know that a function should not change the value of an argument, but don’t want to pass by value, the best solution is to pass by const reference.
You already know that a const reference is a reference that does not allow the variable being referenced to be changed. Consequently, if we use a const reference as a parameter, we guarantee to the caller that the function will not (and can not) change the argument!
The following function will produce a compiler error:
void foo(const int &x)
{
x = 6; // x is a const reference and can not be changed!
}
Using const is useful for several reasons:
- It enlists the compilers help in ensuring values that shouldn’t be changed aren’t changed.
- It tells the coder whether they need to worry about the function changing the value of the argument
- It helps the coder debug incorrect values by telling the coder whether the function might be at fault or not
Rule: Always pass by const reference unless you need to change the value of the argument
Summary
Advantages of passing by reference:
- It allows us to have the function change the value of the argument, which is sometimes useful.
- Because a copy of the argument is not made, it is fast, even when used with large structs or classes.
- We can pass by const reference to avoid unintentional changes.
- We can return multiple values from a function.
Disadvantages of passing by reference:
- Because a reference can not be made to a literal or an expression, reference arguments must be normal variables.
- It can be hard to tell whether a parameter passed by reference is meant to be input, output, or both.
- It’s impossible to tell from the function call that the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.
- Because references are typically implemented by C++ using pointers, and dereferencing a pointer is slower than accessing it directly, accessing values passed by reference is slower than accessing values passed by value.
7.4 — Passing arguments by address
|
Index
|
7.2 — Passing arguments by value
|
7.4 — Passing arguments by address
Index
7.2 — Passing arguments by value
Post in which I catch an error can be deleated if you like. Well, it’s your site, so you know that. I’m just saying, you fixed the problem, and so my comments now moot. If you want to keep the comments section cleaner and more relevant to questions or what have you, know, I don’t mind you deleting my proofreading comments.
By the way, from what I’ve read so far:
If this site was turned into a book, I would definately buy it. Superb work being done here.
Also, I have come across quite a few general verb disagreements etc, but I haven’t pointed them out because it doesn’t really take away from the learning experience.
I’ll probably be reading the rest of the site over the next (well how ever long it takes me). If you want me to point out general spelling errors etc too. I will.
[ By all means, point out anything you see. I want this site to be as good as it can be. As far as producing a book, I may very well do that once I am finished writing the tutorials, if it is economically feasible to do so. In the meantime, enjoy the free content! There are also quite a few different ways to help support the site. Thanks again for all your proofreading efforts! -Alex ]
Great!
dear ALEX, i am a novice to COMPUTERS.(born in 1938)but want to enjoy learning c++. i have tried to understand ” We can pass by const reference to avoid unintentional changes.” but nowhere i find an explanations re.” constant return references”. if i have missed this from your tutorial, please refer it to me. OR enlighten me re. “returning constant references with necessary explanations’ please bear with my ignorance. thanks. i am enjoying your tutorials prabhakar
Prabhakar, I suggest you review the lesson on references to get a better understanding of what references are.
A const reference will not let you change the value it references. Consequently, when we pass an variable by const reference, we are not allowed to change the value of the variable within the function.
dear ALEX, i have already sent u my problem but i am herewith giving u the code i cant understand.
std::istream& operator>>( std::istream& input, Complex& operand2 )
{
…
}
the return type as well as the two parameters are references. how can u explain for providing ” return type as a reference” i am stuck up thanks prabhakar
Returning a value by reference works just like passing a value by reference (except the data is moving from the function to the caller instead of the other way around).
When a value is returned by reference, a reference to the value is returned rather than the value itself. This is most typically done with classes and structs, because returning a reference to a class or struct is fast, whereas making a copy of the class or struct is slow.
Alex, your tutorial is of great value to me. Thanks.
I believe that you made a typo in the first snippet: it should say ‘void AddOne’ instead of ‘int AddOne’.
Cheers.
[ I did indeed! Thanks for catching that. It's fixed now. -Alex ]
I would like a book too. I don’t know if the current books are as good, but I’ll get one eventually. I am going through this tutorial way too quickly to really grasp all the concepts. I should slow down and treat it more like a class. I think i want to speed through it, then come back for seconds. I won’t really learn until I start a real project. I think I will be try to port my MATLAB code over, but it needs pretty much a complete rewrite haha and experimenting with many libraries. I’m not ready yet.
Hello Alex -
This website is very helpful - Thanks! However, since you said above:
“By all means, point out anything you see. I want this site to be as good as it can be.”
I will take this opportunity to point out that a few times you make the common mistake (or maybe just typo) of confusing the word “it’s” with the word “its”: The word “it’s” is a contraction for “it is”, while the word “its” (no apostrophe) shows possession, e.g. “It’s time to learn about the C++ language and its many features.”
If in doubt as to which is correct where, just substitute in “it is” and see if it makes sense - “It is time to learn….” makes sense, but “and it is many features” doesn’t make sense - so use “its” without the apostrophe there.
Sorry if this is pedantic; I know it’s minor, but it is a mistake nonetheless. :)
Examples:
section 6.10: “*pnPtr = 6; // pnPtr treats it’s value as const”
section 7.13: “// Loop through each argument and print it’s number and value”
In both cases, “it’s” should be replaced with “its”.
[ You are correct. I'll get those fixed up. -Alex ]
This example is very good i learn many things by this example thnax …this site helps a lot