Thread: reference operator following return type?

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    14

    reference operator following return type?

    for example

    int& func(int& a);

    i keep seeing it in my book and it assumes you already know what it does, so it must be something basic. What does it do?

    edit:
    ahh, crap, i actually already understood the pass by reference idea, i just got it mixed up with the return type syntax. sorry about that.

    let me ask a different question:
    what type of variable is returned with a int& return type?

    you said it was returning a reference but not a pointer?
    Last edited by thracian; 07-08-2008 at 04:58 PM.

  2. #2
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    It's returning a reference to an int, instead of a direct int or a pointer to an int.

  3. #3
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    Quote Originally Posted by MacGyver View Post
    It's returning a reference to an int, instead of a direct int or a pointer to an int.
    what do you mean by reference? isn't a pointer a reference?

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    A reference is an actual name for something in C++, not a generic term (at least in this case). A reference type is denoted with the & and is in many ways similar to a pointer (but in many ways it is different). If you haven't learned references yet, skip ahead to the chapter on them and read up to get the basic idea, or get a book that explains them better before it uses them.

  5. #5
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Quote Originally Posted by thracian View Post
    what do you mean by reference? isn't a pointer a reference?
    Yes, in a generic sense. No, in a pedantic C++ sense.

    A reference in C++ is a special type of variable that acts as a pointer under the hood.

    For example:

    Code:
    #include <iostream>
    
    void inc(int a);
    
    void inc(int a)
    {
        a++;
    }
    
    int main()
    {
        int x = 5;
        inc(x);
    
        std::cout << "x = " << x << std::endl;
    
        return 0;
    }
    If you ran this code, you'll get 5, even though the var it has is incremented. The reason is that a copy of x is really given to inc(), not x itself. This means that inc() is playing with a temporary variable and not changing anything back in main().

    If you changed the code so inc() took a reference, then that means the output would be 6, because a reference binds a particular variable to another one. In that case, inc() would be playing with the same variable x.

    References are really implemented as pointers, however, that is hidden from you as a programmer. You let the compiler worry about the details.

    References are safer in the sense that you can't receive a NULL pointer. You know automatically the reference refers to some variable. It can be a little tricky since there is no way to tell if a function is passing by reference or passing by value if you just look at a function call without seeing the function prototype.

  6. #6
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    ahh, crap, i actually already understood the pass by reference idea, i just got it mixed up with the return type syntax. sorry about that.

    let me ask a different question:
    what type of variable is returned with a int& return type?

    you said it was returning a reference but not a pointer?

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    A reference is an actual thing. It is like a pointer in that you add a symbol to the type to indicate that you want the variable to be a reference to that type, but it is a completely separate thing in C++.
    Code:
    int* this_function_returns_a_pointer_to_int();
    Code:
    int& this_function_returns_a_reference_to_int();

  8. #8
    Registered User
    Join Date
    Jun 2008
    Posts
    17
    This example might help you see what int & would be returning.

    Code:
    int& func(int &a)
    {
        return a;
    }
    
    int main()
    {
        int *a = new int(1);
        int *t;
        t = &(func(*a));
        *a = 10;
    
        cout<<"Value of t: "<<*t<<endl
            <<"Value of a: "<<*a<<endl;
    
        delete a;
    
        return 0;
    }
    The output is

    Code:
    Value of t: 10
    Value of a: 10
    The behavior of references made more sense to me once I started messing around with pointers. Since "a" and "t" are both integer pointers, what effectively happened is func() made the pointer "t" point to the same memory that "a" is pointing to.

    If "a" and "t" are NOT pointers, the code will be modified like this

    Code:
    #include<iostream>
    
    using namespace std;
    
    int& func(int &a)
    {
        return a;
    }
    
    int main()
    {
        int a = 1;
        int t;
        t = func(a);
        a = 10;
    
        cout<<"Value of t: "<<t<<endl
            <<"Value of a: "<<a<<endl;
    
        return 0;
    }
    And the output will be
    Code:
    Value of t: 1
    Value of a: 10
    In this case, IMO, it's pointless to have function return by reference. However, if you are working on embedded software, writing a kernel, or device driver the memory saving might be worth the strange looking function.

    HTH

  9. #9
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    Code:
    #include <iostream>
    using namespace std;
    
    
    int& func(int a){ return a;}
    
    int main(){
        
    int x =1;
    
    cout <<"&x: "<<&x<<endl
    <<"func(x): "<< func(x)<<endl
    <<"&func(x): "<<&func(x);
    
    
    system("pause");
    return 0;   
    }
    pantherse - I understand that when you pass by reference, you're passing the memory location instead of the copy of the value.

    Can you explain that code though?

    output:
    &x: some address
    func(x): 4469696
    &func(x): some different address


    i'm just trying to understand what kind of value is returned with a reference return type. why is it different?
    Last edited by thracian; 07-08-2008 at 04:59 PM.

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    The code you posted is wrong thracian, and different than pantherse's code. In your code, the parameter to func is an int, but in pantherse's code it is a reference to int.

    The reason this matters is because func then returns a reference to that variable. So in pantherse's code, a refers to x and so the func function returns a reference to x. In your code, a is a copy of x, so the func function returns a reference to that copy. But the copy is destroyed when the function ends and so it returns a reference to a destroyed variable. This causes undefined behavior, meaning you can't really figure out anything from what happens because the code is wrong.

    Try it again with:
    Code:
    int& func(int& a){ return a;}

  11. #11
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    Quote Originally Posted by Daved View Post
    The code you posted is wrong thracian, and different than pantherse's code. In your code, the parameter to func is an int, but in pantherse's code it is a reference to int.

    The reason this matters is because func then returns a reference to that variable. So in pantherse's code, a refers to x and so the func function returns a reference to x. In your code, a is a copy of x, so the func function returns a reference to that copy. But the copy is destroyed when the function ends and so it returns a reference to a destroyed variable. This causes undefined behavior, meaning you can't really figure out anything from what happens because the code is wrong.

    Try it again with:
    Code:
    int& func(int& a){ return a;}
    There are instances in my book where the reference operator follows the return type and not the arguement type which is the source of this confusion.

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Yes, and it is allowed in some instances depending on the reference refers to. However, here you are returning a reference to the argument, so when that argument is a plain int it will be destroyed.

    Returning a reference to a local variable is wrong. Any valid example that returns a reference is returning something other than a local variable. So you can't look at your example because it just isn't valid C++.

    An important thing to understand is object lifetime. A local variable (like the parameter in your example) is destroyed at the end of its block of code. You can't use a reference or pointer to a destroyed variable.

  13. #13
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    Quote Originally Posted by Daved View Post
    Yes, and it is allowed in some instances depending on the reference refers to. However, here you are returning a reference to the argument, so when that argument is a plain int it will be destroyed.

    Returning a reference to a local variable is wrong. Any valid example that returns a reference is returning something other than a local variable. So you can't look at your example because it just isn't valid C++.

    An important thing to understand is object lifetime. A local variable (like the parameter in your example) is destroyed at the end of its block of code. You can't use a reference or pointer to a destroyed variable.
    So with my example is the reference some random memory location or where the destroyed variable used to exist? If it's where it used to exist, why isn't func(x)=1?

  14. #14
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    It's undefined behavior. Anything can happen. On my machine it is 1 because it probably does just return the location that the variable used to have. Perhaps your compiler is clearing out the data in that memory location or is pointing to a random memory location. It shouldn't really matter, though, because it's invalid code. It might change behavior the next time you change it or the next time you compile it or the next time you run it.

  15. #15
    Registered User
    Join Date
    Jun 2008
    Posts
    17
    Quote Originally Posted by thracian View Post
    Code:
    #include <iostream>
    using namespace std;
    
    
    int& func(int a){ return a;}
    
    int main(){
        
    int x =1;
    
    cout <<"&x: "<<&x<<endl
    <<"func(x): "<< func(x)<<endl
    <<"&func(x): "<<&func(x);
    
    
    system("pause");
    return 0;   
    }
    pantherse - I understand that when you pass by reference, you're passing the memory location instead of the copy of the value.

    Can you explain that code though?

    output:
    &x: some address
    func(x): 4469696
    &func(x): some different address


    i'm just trying to understand what kind of value is returned with a reference return type. why is it different?
    I'd be delighted to explain the code. However, this is going to be a long-winded answer because I'm going into under-the-hood stuff.

    &x prints the memory location for variable x, which in this case contains the value 1.

    Code:
    <<"func(x): "<< func(x)<<endl
    should have printed "1", which is the value of x that was passed to func() but it didn't. What happened is that the execution of func() completed and returned the memory address that "a" used to occupy. However, before the value was printed your kernel decided that it'll put your program on hold, and let another process run. For whatever reason, the kernel gave the memory address that func() returned to that process who wrote something else in the same location. So instead of you getting 1 in your output you got whatever that value was.

    In fact, gcc compiler 4.2.3 (which I used to compile the code you posted) generated the following warning

    Code:
    test2.cpp:5: warning: reference to local variable ‘a’ returned
    The line
    Code:
    <<"&func(x): "<<&func(x)
    actually prints out the memory address of func()'s return value. In this case it's the memory address of "a"

    Other languages like ADA, FORTAN, or Java won't let you get away with these kind of stuff, I personally consider the sample code you gave as sloppy. However, there's a reason why the language allows it. If you are writing an OS kernel or device driver, to name a few, you need to have this flexibility. But if you do this you're basically on your own. The common cause of most software security issues is because of mishandling memory using a language that'll let you do whatever you feel like (even write assembly code as part of your C/C++ code).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  2. Another weird error
    By rwmarsh in forum Game Programming
    Replies: 4
    Last Post: 09-24-2006, 10:00 PM
  3. Please Help - Problem with Compilers
    By toonlover in forum C++ Programming
    Replies: 5
    Last Post: 07-23-2005, 10:03 AM
  4. problem with open gl engine.
    By gell10 in forum Game Programming
    Replies: 1
    Last Post: 08-21-2003, 04:10 AM
  5. Dynamic list of Objects in External File
    By TechWins in forum C++ Programming
    Replies: 3
    Last Post: 12-18-2002, 02:05 PM