简体   繁体   中英

Rvalues, Lvalues and references confusion

I've been trying to understand rvalues, lvalues and references and their usage as a returning values of functions (methods) so i created few small examples for practice purpose.

So firstly, i came up with this code (after reading somewhere, possibly here, that whenever i have a "regular" (without reference) return value for some method, it is considered to be rvalue, exception is when i add reference operator sign in the return value, like in this example:

#include <iostream>

int x = 5;
int& References()
{

    return x;
}

int main()
{ 
    References() = 3;

    std::cout << x;

    getchar();
    getchar();
}

So here, function References returns lvalue when called, and this code works out just fine, however, since this works, i thought that i can do something similar other way around, and this is what i tried:

#include <iostream>

int x = 5;
int References()
{

    return x;
}

int main()
{ 
    int a = References();

    std::cout << a;

    getchar();
    getchar();
}

This code works just fine, the output is 5, which means that i successfully assigned value to the variable a, which is something i expected since this function returns "ordinary" integer so it a rvalue.

HOWEVER, when i once again add reference operator sign to the return value of function References, again, it works fine:

#include <iostream>

int x = 5;
int& References()
{

    return x;
}

int main()
{ 
    int a = References();

    std::cout << a;

    getchar();
    getchar();
}

So, even though my function now returns int& which is returned as lvalue, this code still works and the output is still 5, which means that i managed to assign the value to my variable a successfully. What is going on here? Any help appreciated!

When you use a reference in an expression or an assignment, it evaluates out to what the reference refers to, not the memory address, which I suppose is what you expect to see.

Compare the output of the following functions:

int x = 5;
int& Reference()
{
    return x;
}

int *Pointer()
{
    return &x;
}


int main()
{
    std::cout << Reference() << std::endl;
    std::cout << Pointer() << std::endl;
    return 0; 
}

When you return by reference you have an lvalue , when you return by value you have a prvalue . In your case the difference you can read from both of them, but cannot assign to prvalue , not clear where is your confusion coming from:

int i1 = lvalue; // fine
int i2 = prvalue; // fine

but:

lvalue = 123; // fine
prvalue = 123; // error

closer to your case:

int &func1();
int func2();

int i1 = func1(); // fine
int i2 = func2(); // fine

func1() = 123; // fine
func2() = 123; // error

more info: Value Category

According to https://learn.microsoft.com/en-us/previous-versions/f90831hc(v=vs.140) : You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.

The third example is exactly the same as the second one, it's copying the value. You can copy a value from an lvalue just how you can copy a value from an rvalue. If your a variable was of type int& instead, you wouldn't be copying the actual value, you'd just get the same reference. This might help you understand:

#include <iostream>

int x = 5;
int& References()
{

    return x;
}

int main()
{ 
    int a = References();
    int& b = References();

    std::cout << a; // 5
    std::cout << b; // 5
    std::cout << x; // 5

    a = 6;
    b = 7;

    std::cout << a; // 6
    std::cout << b; // 7
    std::cout << b; // 7


    getchar();
    getchar();
}

For comparison:

int  n = 10;
int& r = n;
int* p = &n;

int x = n;  // copy by value
int y = r;  // copy by value, too, use the variable referenced as source
int z = *p; // copy by value third time, using variable pointed to

int& r0 = r; // copy the reference, i. e. r0 now references n as well
int* p0 = p; // copy the pointer...

n = 12;
// now x, y, z all STILL have value 10!
// r, r0, *p and *p0, in contrast, all yield 12

Not different with functions:

int& ref() { return n; }
int val() { return n; }

int& r1 = ref(); // copy the reference, again r1 references n!
int& r2 = val(); // INVALID!!!
// the latter is comparable to:
int& r3 = 7;     // invalid...

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