Navigation



7.3 — Passing arguments by reference

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 <iostream>
#include <math.h>    // for sin() and cos()

void GetSinCos(double dX, double &dSin, double &dCos)
{
    dSin = sin(dX);
    dCos = cos(dX);
}

int main()
{
    double dSin = 0.0;
    double dCos = 0.0;

    // GetSinCos will return the sin and cos in dSin and dCos
    GetSinCos(30.0, dSin, dCos);

    std::cout << "The sin is " << dSin << std::endl;
    std::cout << "The cos is " << dCos << std::endl;
    return 0;
}

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 structs 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 non-const 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

48 comments to 7.3 — Passing arguments by reference

  • [...] — Const class objects and member functions By Alex In the lesson on passing arguments by reference, we covered the merits of passing function parameters as const variables. To recap, making [...]

  • Jason

    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 ]

  • [...] Jason: Post in which I catch an error can be deleated if you like. Well, it’s your site, so you know that…. [...]

  • PRABHAKAR

    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.

  • PRABHAKAR

    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.

  • BP

    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 ]

  • Chad

    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.

  • Tom

    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 ]

  • [...] 2007 Prev/Next Posts « 6.13 — Void pointers | Home | 7.3 — Passing arguments by reference » Monday, July 23rd, 2007 at 6:59 [...]

  • parveen thakran

    This example is very good i learn many things by this example thnax …this site helps a lot

  • surya

    hai alex.fantastic explanation. n

  • javid

    Superub website to learn c++…great going alex….

  • Alan Hurley

    allows us to pass large stucts and classes with a minimum performance penalty.

    should read:

    allows us to pass large structs and classes with a minimum performance penalty.

    [ Fixed. Thank you! -Alex ]

  • Mina

    Because a reference can not be made to a literal or an expression, reference arguments must be normal variables.

    You mentioned when you introduced references that a const reference can be made to a literal constant but that there’s usually no point in doing so, e.g.

    const int &x = 5;

    And passing a literal constant as an argument to a function whose parameter is a constant reference worked fine for me.

    Can you clarify if I misunderstood you?

    Thanks for these phenomenal tutorials. A very generous gift to the online community.

  • Gareth37
    #include <math.h>    // for sin() and cos()
    
    void GetSinCos(double dX, double &dSin, double &dCos)
    {
        dSin = sin(dX);
        dCos = cos(dX);
    }
    

    Alex i’m having trouble grasping this code, i put it in visual studio and then thought how do i call the GetSinCos function from main ? i cant pass it the arguments because i dont know what &dSin and &dCos are and it wont let me call it with one argument of dX and it also fails to compile if i enter some spurious values for &dSin and &dCos hoping they would get overwritten by the dSin = sin(dx) calculation.
    i realise i am probably doing something fundamentally wrong (i feel a bit like a monkey trying to build a rocketship but i’m having a go anyway) i have this -

    #include "stdafx.h"
    #include <math.h>    // for sin() and cos()
    
    void GetSinCos(double dX, double &dSin, double &dCos)
    {
        dSin = sin(dX);
        dCos = cos(dX);
    }
    
    int main()
    {
       GetSinCos(30.0, 5.0 ,6.0);
    	return 0;
    }
    

    its all wrong but why ?

    • I think what you are missing here is that dSin and dCos are meant to be “out” parameters — that is, their values are being calculated by the GetSinCos() function and returned to the caller.

      Note that both dSin and dCos are non-const REFERENCE parameters. This means you MUST pass them a variable that has an address. So you should use the following code:

      double dSin;
      double dCos;
      
      GetSinCos(30.0, dSin, dCos);
      

      I will update the example to make this clearer.

    • sujitbista

      The value assigned in dsin and dcos is returned to reference &dsin and &dcos which in turn passes the value to the calling fuction in the main program. So the code goes like this

      void main()
      {
      GetSincos(30.0,dSin,dCos);
      cout<<"The value of dSin is"<<dSin<<endl;
      cout<<"The value of dcos is"<<dCos;
      }

  • Mike

    Hey man,

    great post dude. I never understood these things ’till I read this. Thanks man :D

  • The snipped near the start of the page including the Addone() function will print everything there except for the ;’s. So I think you should remove that. Correct me if I’m wrong.

    • Quinn

      The semicolons (;) at the end of the statements signify to the compiler the end of the command (this lesson introduced them). They’re necessary to put there, every program must include them at the end of its statements, and this includes cout. So the code

      #include <iostream>
      
      int main()
      {
          int x = 1
          std::cout << x
          return 0
      }

      will not work. You need to include the semicolons at the end. The code

      #include <iostream>
      
      int main()
      {
          int x = 1;
          std::cout << x;
          return 0;
      }

      will.

      Always remember to try experimenting the code he’s provided you out on your own compiler! Check here for some good ones with easy to use IDE’s (if you’re on Linux, your distro usually has good ones preinstalled or available over it’s package manager, and on Mac OSX you should look up XCode). Don’t worry too much if the IDE doesn’t make sense right away, by growing accustomed to the language, you’ll find more and more need for your IDE to perform different tasks, and usually, the IDE provides ways to do just those things. :) Besides, it’s much easier in an IDE to simply press the “Build + Run” button instead of having to compile through the command line (but it’s certainly not impossible).

  • eric

    In the 2nd example,

    using namespace std;

    is missing from main().

    These are fantastic tutorials, I just started learning C++ a couple of days ago and the basics have flown by with these. Thanks for all your hard work putting these together!

  • hey Alex i have i doubt on use of references. Like if we can perform our work through pointer why we need references.Like why we use const. reference if we can achieve the same with const. pointer to const. data.

    :)

  • [...] 7.3 Passing arguments by reference [...]

  • bla

    “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.”

    What is meant by accessing it directly? The value or the reference. If it should be reference I could use some further explanation… The way I understood the sentence is, that once the value is copied, it can be accessed easily.

    Btw I should mention that I like this site very much. Especially the quizzes, though there could be more of them ;-)

    • ““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.”

      What is meant by accessing it directly? The value or the reference. If it should be reference I could use some further explanation… The way I understood the sentence is, that once the value is copied, it can be accessed easily.”

      You might translate this as “… is slower than directly accessing the value that the pointer/reference refers to”.

      So:

      int i;
      int n=10;
      int directVals[n] = 0;
      int pVals = &directVals;
      
      for (i=0; i<n; i++) {
        directVals[i] = 1 // A - direct access is faster
        *pVals[i] =1       // B - accessing through de-referenced pointer is a little slower than A
      }
       

      But, this speed to access data must be balanced against the time that it takes to copy data into a "direct" variable, as in pass-by-value. For large n, the suggestion is that the copy time will outweight the speed-of-access time. What's the break-even threshold? Good question!

  • Tom

    It tells the coder whether they need to worry about the function changing the value of the argument

    —> It tells the coder whether he needs to worry about the function changing the value of the argument

  • [...] KNOWLEDGE FOR THIS PROGRAM Functions Passing a Value By Reference Structures Constant Variables Boolean Expressions [...]

  • [...] the lesson on passing arguments by reference, we briefly mentioned that references are typically implemented by the compiler as pointers. [...]

  • [...] KNOWLEDGE FOR THIS PROGRAM Functions Passing a Value By Reference Integer Arrays Structures Constant Variables Boolean [...]

  • [...] PROGRAM Header Files – How To Use Them Class – Data Structure Enumerated List Typedef Do/While Loop Passing a Value By Reference Constant Variables Atoi – Convert String To Int [...]

  • [...] KNOWLEDGE FOR THIS PROGRAM Header Files – How To Use Them Class – What Is It? Do/While Loop Passing a Value By Reference Roman Numerals – How Do You Convert To Decimal? Online Roman Numeral Converter – Check For Correct [...]

  • etam

    “Rule: Always pass by const reference unless you need to change the value of the argument”
    It’s not quite true. When passing small things like built-int types, or small structures like a pair of built-in types, it’s faster to copy them, than to pass reference or pointer. It allows compiler for better optimizations.

  • [...] C# has a struct keyword that enables you to define objects that are always copied instead of being passed by reference. While Java has primitives like int, and byte, custom value types aren't supported. While reference [...]

  • [...] we add the std::list& results as a parameter to our previously coded function and we will add code to store our results [...]

  • [...] the lesson on passing arguments by reference, we briefly mentioned that references are typically implemented by the compiler as pointers. [...]

  • [...] the lesson on passing arguments by reference, we covered the merits of passing function parameters as const variables. To recap, making [...]

  • JohnM

    I copied and pasted the following into Microsoft Visual C++ 2010 Express and ithe output is not correct. The output for 45 degress is show below my program.

    Can you help me understand why?

    // Passing_multiple_arguments.cpp : Defines the entry point for the console application.
    //

    #include “stdafx.h”
    #include
    #include // for sin() and cos()

    void GetSinCos(double dX, double &dSin, double &dCos)
    {
    dSin = sin(dX);
    dCos = cos(dX);
    }

    int _tmain(int argc, _TCHAR* argv[])

    {
    double dSin = 0.0;
    double dCos = 0.0;

    // GetSinCos will return the sin and cos in dSin and dCos
    GetSinCos(45.0, dSin, dCos);

    std::cout << "The sin is " << dSin << std::endl;
    std::cout << "The cos is " << dCos << std::endl;

    return 0;
    }

    /*
    OUTPUT is:

    The sin is 0.850904
    The cos is 0.525322

    */

  • I NOTICED THAT DE PROGRAM DOES NOT GIVE THE DE CORRECT ANSWER OF COS 30 AND SIN 30

    …. R …

    I LEARNT A NEW LESSON AS WELL.

    THANKS

You must be logged in to post a comment.