Thread: References? When should I use them? And why?

  1. #1
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171

    Question References? When should I use them? And why?

    Hi! C++ programmers! I have questions about references and that questions are:

    When should I use them?
    What is the reason to use a reference?

    I know that I should use a reference whenever possible instead of using a pointer.
    I understand the syntax of references but not why I should use them? And what's the reason to use a reference?

    I had a code in the book that I read that look like this as an example of a function with parameter references

    Code:
    #include <iostream>
    
    
    using namespace std;
    
    
    void badSwap(int x, int y)
    {
        int temp = x;
        x = y;
        y = temp;
    }
    
    
    void goodSwap(int& x, int& y)
    {
        int temp = x;
        x = y;
        y = temp;
    }
    
    
    int main()
    {
        int arg1 = 12;
        int arg2 = 22;
        badSwap(arg1, arg2);
        cout << "badSwap(): " << "X: " << arg1 << " Y: " << arg2 << endl;
        goodSwap(arg1, arg2);
        cout << "goodSwap(): " << "X: " << arg1 << " Y: " << arg2 << endl;
        return 0;
    }
    So I have a function called badSwap() which outputs the lowest score first and the highest last. And the function takes two arguments that is two int variables.

    And I have a function called goodSwap() that takes two int references as arguments. I have exactly same code in their function body but their behaviors are diffrent from each other?
    I don't understand why them are diffrent? One of them returns the value 12, 22 and the other one 22, 12??

    Why is that? Shouldn't the functions do the same thing? I need to know why them behave like that I didn't really understand why even if I read that pages many times.

    And I'm wondering when should I use references and why are they efficient?
    Last edited by DecoratorFawn82; 12-28-2013 at 04:39 PM.

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Actually one of the functions doesn't return anything. The functions themselves do do the same things, the difference is that one of the functions return the results and the other doesn't.

    I suggest you study the following tutorial: Functions pay particular attention to the section titled: "Arguments passed by value and by reference".

    Jim

  3. #3
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Effectively, references are an alternate syntax for pointers to variables, except the calling code looks like it's passing variables instead of pointers to variables. One disadvantage of this is on a large project with multiple source files and separate include files, where you have to find the function prototype in order to find out if it's using references for any of it's parameters.

    As for bad swap versus good swap, bad swap parameters are passed by values, it's getting a copy of the contents of the variables, so it doesn't change the caller's variables. Good swap parameters are passed by references, which are effectively pointers to the parameters so it changes the caller's variables.

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Arguments of badSwap() are passed by value. So the call badSwap(arg1, arg2) passes copies of the values of arg1 (12) and arg2 (22) to badSwap(). The changes made in badSwap() are therefore local to that function, and are not visible to the caller.

    Arguments of goodSwap() are passed by reference. The changes made in goodSwap() are therefore visible to the caller.

    If you want the behaviour of goodSwap() it is necessary to pass by reference.

    You could also get exactly the same affect with goodSwap() by changing main() to
    Code:
    int main()
    {
        int arg1 = 12;
        int arg2 = 22;
        badSwap(arg1, arg2);
        cout << "badSwap(): " << "X: " << arg1 << " Y: " << arg2 << endl;
        {
             int x = arg1, y = arg2;    // create copies of arg1 and arg2 to be passed to goodSwap()
             goodSwap(x, y);            // arg1 and arg2 are unaffected
        }    // x and y no longer exist from here
        cout << "goodSwap(x,y): " << "X: " << arg1 << " Y: " << arg2 << endl;
        return 0;
    }
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I've always sort of followed the rule that I only pass by reference when passing by value won't do what I want. For example, if I actually want to modify a variable, I'll pass by reference otherwise if I just need a copy, passing by value will do.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    You should also consider passing by reference when passing expensive to copy classes/structures. Using the proper const qualifiers if required.


    Jim

  7. #7
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171
    Hmm . . . I'm think I got how this works now. The function badSwap() creates copies of the variables and it is the copies that changes values within the function not the "real" variables because the function have created to copies of them.

    But the other function doesn't copy the variables. Instead it takes the "real" variables and changes their values

  8. #8
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    No, it changes values at an address. There is no "real" or "fake" here, just different addresses with different values.

  9. #9
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171
    Yeah, in one function it just happens something with the variables that has been copied and in the other one it happens with the variables that the goodSwap() function takes as arguments

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You're missing MutantJohn's point, albeit it is a slightly subtle one. The catch is that his interpretation is always correct, whereas yours breaks down (and doesn't always work) sometimes.

    Every function argument (or parameter) is passed by value in C++. The difference is in what the passed value means.

    With "pass int by value", it is the value of the int supplied by the caller that is passed. The function can change the value passed, but the change is not visible to the caller. This is what happens in your badSwap().

    With "pass int by reference", the value passed to the function is a reference - which is a proxy that can be used to directly access the int supplied by the caller. It is not possible to change the reference (i.e. make it a proxy for a different int) but it is possible to change what it references. This is what your goodSwap() does, so the changes made are visible to the caller.

    There is also a "pass int by pointer", in which the value passed to the function is a pointer - who's value is the address of an int, so it can be used as a proxy to indirectly access the int supplied by the caller (the "indirectly" is in red, because this is the fundamental difference between a pointer and a reference). The function can change the pointer, but the change of pointer is not visible to the caller. However, the function can also dereference the pointer - which allows changing the int who's value is supplied by the caller.
    Code:
    void goodSwapByPointer(int *x, int *y)
    {
         int temp = *x;       //   *x is a reference to the int supplied by the caller
         *x = *y;
         *y = temp;
    } 
    
    int main()
    {
        int arg1 = 12;
        int arg2 = 22;
        goodSwapByPointer(&arg1, &arg2);      //   & is "address of" operator
    
          //   arg1 will have value 22 here, and arg2 will be 12
    }
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by grumpy
    Every function argument (or parameter) is passed by value in C++. The difference is in what the passed value means.
    I don't agree with this statement. The way I see it, if a formal parameter is of reference type, then a corresponding actual argument is passed by reference, hence we have call by reference. If a formal parameter is of pointer type, then a corresponding actual argument is still passed by value, but we have achieved call by reference with respect to what the pointer points to.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Every function argument (or parameter) is passed by value in C++.
    Another exception is an array, which C and C++ pass as a pointer to the array, instead of the values in the array.

    Another possible advantage of pass by C++ reference instead of pass by pointer is if global optimization by a C++ compiler would keep a register based variable in the same register when passed by reference, (as opposed to using a pointer which would normally force the variable to be memory based).

  13. #13
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by laserlight View Post
    I don't agree with this statement. The way I see it, if a formal parameter is of reference type, then a corresponding actual argument is passed by reference, hence we have call by reference. If a formal parameter is of pointer type, then a corresponding actual argument is still passed by value, but we have achieved call by reference with respect to what the pointer points to.
    Two references are only identical if they refer to the same object. When two distinct variables are passed by reference, there must be some information unique to each variable passed to the function, by which it can access the original variables (i.e. get their value, or change their value in the case of non-const references). That is the information that may be considered as being passed by value.


    Quote Originally Posted by rcgldr View Post
    Another exception is an array, which C and C++ pass as a pointer to the array, instead of the values in the array.
    It's not an exception.

    An array is passed as a pointer, according to rules of the language (in which the name of an array is converted to a "pointer to element" with value equal to address of first element of the array).

    A reference to an array (of n elements of specified type) is still a reference. And a pointer to an array is still a pointer. The type of the reference (or pointer) is different though (i.e. "pointer to array of 6 int" is of different type to "pointer to int").

    Quote Originally Posted by rcgldr View Post
    Another possible advantage of pass by C++ reference instead of pass by pointer is if global optimization by a C++ compiler would keep a register based variable in the same register when passed by reference, (as opposed to using a pointer which would normally force the variable to be memory based).
    Maybe. A compiler is permitted to ignore the register keyword, and it is the compiler that decides what is placed in registers (based, directly or indirectly, on type information and values available at compile time), so I doubt there would be a difference in that regard.

    The more usual cited advantage is that a compiler has early optimisation opportunities since it is permitted to assume, within the body of a function, that a supplied reference is to an object that exists (since any code that creates a reference to a non-existent object - whether to pass it to a function or not - invokes undefined behaviour).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by grumpy
    When two distinct variables are passed by reference, there must be some information unique to each variable passed to the function, by which it can access the original variables (i.e. get their value, or change their value in the case of non-const references). That is the information that may be considered as being passed by value.
    That is not the same as saying that "every function argument (or parameter) is passed by value in C++" since you're talking about implementation detail, i.e., the information that is "passed by value" is not the argument, at least conceptually.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by laserlight View Post
    That is not the same as saying that "every function argument (or parameter) is passed by value in C++" since you're talking about implementation detail, i.e., the information that is "passed by value" is not the argument, at least conceptually.
    Okay - can accept that.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. using references (need help)
    By dhardin in forum C++ Programming
    Replies: 9
    Last Post: 12-29-2009, 05:07 PM
  2. References
    By Dae in forum C++ Programming
    Replies: 7
    Last Post: 07-23-2009, 03:29 AM
  3. References
    By Lurker in forum C++ Programming
    Replies: 7
    Last Post: 12-23-2003, 12:01 PM
  4. Help via references please!
    By Matt13 in forum C Programming
    Replies: 5
    Last Post: 11-11-2003, 08:09 AM
  5. declare references to references works!
    By ManuelH in forum C++ Programming
    Replies: 4
    Last Post: 01-20-2003, 08:14 AM