简体   繁体   中英

C++ Function Return/Input Reference Type

I'm way too confused of reference return/input types. I think I can best ask my question by explaining my understanding.

When a reference is input to a function as an argument as below...

void squareByReference( int & );

int main ()
{
    int z = 4;
    sequareByReferece( z );

    return 0;
}

int squareByReference( int &numberRef )
{
   numberRef *= numberRef;
}

I understand it as in the 'squareByReference,' &numberRef is received by the function as an address to an int variable, but 'somehow' can be recognized and treated just like a normal int variable. Therefore, the line 'numberRef *= numberRef; can treat numberRef as a normal int even though it's actually an address.

I'm okay with this. I get it and no problem interpreting/coding programs.

However, when it comes down to reference return, it makes me confused too much.

int g_test = 0;

int& getNumberReference()
{
    return g_test;
}

int main()
{
    int& n = getNumberReference();

    n = 10;
    std::cout << g_test << std::endl; // prints 10
    std::cout << getNumberReference() + 5 << std::endl; // prints 15

    return 0;
}

My confusion is this: Why is 'n' defined as a reference int variable?! Following my previous logic, the getNumberReference() returns a reference variable, and even though it is actually an address to an int, it should be 'somehow' treated as equal to normal int variable. Therefore, it should be saved in int variable not reference to int variable! This logic works perfectly fine when it comes to the line 'std::cout << getNumberReference() + 5 << std::endl;.' It is 'somehow' treated as a normal int variable and prints 15.

Could you please correct my understanding to resolve my question on int& definition???

When you are talking about references, you have to differentiate between syntax and semantics. The syntax for references - once they are initialized/bound to an object - is almost the same as for normal variables. Their semantic however is more similar to pointers and - as far as function parameters and return types are concerned - are typically implemented in exactly the same way.

Function Parameters
Passing a reference as a function parameter means that every time you access that variable, you actually access the original object, the same way as you would if you'd pass a pointer and dereference it. Now inside a function you will usually see no difference between pass by value or pass by reference, as (in single threaded code) you are the only one to change the contents of that variable anyway and so it doesn't matter for you whether you are working on the actual object or a copy. One situation, where this is no longer true is if the parameter aliase each other:

void foo(int& a, int& b) {
    a=1;
    std::cout << b << std::endl;
}  
int main() {
    int p=2;
    foo (p,p); //this will print 1 instead of 2;
}

And of course it does always matter outside the function, because with pass-by-references you changed the original object outside the function and with pass-by-value you only changed a local copy.

Function return values
Nothing prevents you from writing:

int n = getNumberReference();

in which case the returned reference would be treated as a "normal int variable", so n would end up to be a copy of that object and you would print 0 and 5 instead.
What you are doing, however, is to create a new reference and bind it to whatever getNumberReference() returns. If getNumberReference would return a plain int, your program would run into undefined behavior, as you are referencing a temporary variable that doesn't exist past the semicolon anymore. However, your code is returning a reference instead and n is not bound to the returned reference itself, but to the object that reference references in the first place (like copying a pointer). As it so happens, that object is a global object, whose lifetime exceeds anything inside main , so n can be used safely after the semicolon. As a result, n and g_value are now two names representing the same object in memory and whenever you change that object via one of its names, you can observe that change via the other. Thats why it is usually bad practice, if multiple (non-const) identifiers in one scope aliase the same object.

To sum that up, in most cases it is better to think of references as syntactic sugar for pointers instead of normal variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM