Thursday, May 2, 2013

lvalue and rvalue

/**
 * This example is all about lvalue vs. rvalues. This is an important topic,
 * especially in the context of C++11 which contains rvalue references. That's
 * a bigger topic for later.
 *
 * lvalue's:
 * - An object that persists beyond a single expression [1].
 * - An object that has a name [1].
 *
 * rvalue's:
 * - Can evaluate to a temporary value [1].
 * - Do NOT represent an object occupying an identifiable location in memory [2].
 *
 * I've enclosed parts of the program that do not compile inside of error
 * macros. You can uncomment one at a time to see what happens when we use
 * non-modifiable lvalues or assign to rvalues.
 */

#include <iostream>

//#define ERROR

//#define ERROR2

//#define ERROR3

//#define ERROR4

//#define ERROR5

//#define ERROR6

//#define ERROR7

//#define ERROR8

struct S1;

/**
 * This is a struct that will be a non-modifiable lvalue when created. Just
 * come back to this after you get down a ways.
 */
struct S2
{
    int value1;
    #if defined ERROR5
    double const value2; //< This is what makes it non-modifyable.
    #endif
    double value3;

    S2()
    : value1(0)
    #if defined ERROR5
    , value2(13.4)
    #endif
    , value3(7)
    {
    }
};

int main(int, char**)
{
    int magicNumber;

    // Let's first consider assignment. Assignment must have a left hand
    // side with an lvalue, and a right hand side that is an rvalue:
    magicNumber = 12234;

    // magicNumber is an lvalue, it persists to the end of main AND it
    // has a name.
    // 12234 is an rvalue, it only exists inside the context of the
    // assignment.

    // With assignment it is simple to see the conflict if we treated
    // rvalues as lvalues:
    #if defined ERROR

    12234 = magicNumber;
   
    // Clearly this is an error! A number is not a variable or a place that
    // can store anything. It is the most basic rvalue.
    #endif

    // I started to feel comfortable with this lvalue/rvalue stuff until
    // I encountered:
    int const myConstantMagicNumber = 13;

    // I thought to myself, this is clearly an rvalue- you can't put it on the
    // left hand side of an assignment. I wouldn't have cared much about this
    // except the documentation several places makes the distinction between
    // "modifiable" lvalues and "non-modifiable" lvalues:

    // Non-Modifiable lvalues include [3]:

    //// - Array Types.
        #if defined ERROR2
        // The following yields an error where it states:
        // "invalid array assignment", verified this.
        int myNums1[13];
        int myNums2[13];
        myNums1 = myNums2;
        #endif


    //// - Incomplete Types.
        #if defined ERROR3
        S1* s1 = 0;
        S1* s2 = 0;

        // This is obviously not good. Produces:
        // "invalid use of incomplete type S1"
        *s1 = *s2;

        #elif !defined ERROR5

        // This is only for demonstrative purposes (and provided that ERROR5 is
        // also not enabled).
        S2* s2_3 = new S2();
        S2* s2_4 = new S2();
       
        // This is the same above, except the class is defined!
        *s2_3 = *s2_4;

        delete s2_3;
        delete s2_4;

        #endif

    //// - Const-Qualified Types
        #if defined ERROR4

        // Produces error: "assignment of read only value"
        int const s1 = 15;
        s1 = 18;   

        #endif

    //// - Object with Structure or Union Type and one member is a const-qualified
    ////   type.
        #if defined ERROR5
           
            // Produces: "synthesized method 'S2& S2::operator=(S2 const&)' first required here"
            S2 s1;
            S2 s2;

            s1 = s2;
        #else
            // We can safely perform the copy because all of the members of S2
            // are non-const and the operator= can safely be generated.
            S2 s2_1;
            S2 s2_2;
            s2_1 = s2_2;
        #endif


    // It's easy to see how we can get confused between modifiable lvalues, non-modifiable
    // lvalues, and rvalues. Each of the four examples above shows an lvalue (named and
    // they persist) but are NOT modifiable. Here are some other cool examples of lvalues
    // that are modifiable:

    int* myValue = &magicNumber;   
    *myValue; // The pointer to myValue is a modifiable lvalue.

    // This is by far the coolest example of lvalues around. It uses the ternary operator
    // but does indeed evaluate to an lvalue! [4]
    int a = 0;
    int b = 0;
    (magicNumber < 10 ? a : b) = 17;
    std::cout << "a = " << a << ", b = " << b << std::endl;

    // You should check out the table in reference [3] about certain operators and whether
    // or not they work on lvalue's or rvalue's:

    //// operator& - Operator must be an lvalue
        #if defined ERROR6
        int* addressOfSomething = &7      //< What is an address of 7?
        #else
        int value = 7;
        int* addressOfSomething = &value; //< Requires lvalue!
        #endif

    //// operator++, operator-- - Operator must be an lvalue.
        #if defined ERROR7
        ++7;      //< Failure for both postfix and prefix, they modify a storage
        13++;     //< value.
        #else
        int anotherValue = 7;
        anotherValue++;
        ++anotherValue;
        #endif

    //// =, +=, -=, *=, %=, <<=, >>=, &=, ^==, |= - Left hand side must be lvalue.
        #if defined ERROR8
        7 += 9;                   //< Cannot store back into an rvalue!
        #else
        int yetAnotherValue = 7;  //< Fine because we are modifying an lvalue.
        yetAnotherValue += 9;
        #endif
}

/**
 * In conclusion this is a pretty boring topic but well worth knowing. The subtle
 * nuances between lvalues and rvalues are a good thing to know going into learning
 * about C++11 and the rvalue references. Sorry for the boring entry today!
 */

/**
REFERENCES

[1] - http://msdn.microsoft.com/en-us/library/f90831hc.aspx

[2] - http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c

[3] - http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp

[4] - http://en.wikipedia.org/wiki/%3F:

*/

No comments:

Post a Comment