Lvalue - Rvalue distinctions

Lvalue or location value is an address that is stored into. In the assignment

a = 3;

we have the lvalue of a used on the left hand side and the integer contant value 3 assigned to this location. In the assignment

b = a;

we have the rvalue of a (3) used to assign to the lvalue of b . So depending on which side of an assignment, we use the variable a , we get two different behaviors. In declarations, we can see a difference between lvalue and rvalue in the following declarations:

int dta[3] = {1, 2, 3};
int i = data[0];
int* p = &data[1];
int& last = data[2];

In the first declaration, the array's three locations (lvalues) are initialized to the respective constants. The variable i is initialized to the rvalue of data[0] . The pointer p is initialized to the lvalue of data[1] , in other words, the address of the array element data[1] . The variable last is a reference initialized to the lvalue of data[2]. The pointer p is for the moment another alias for getting to data[1] , but p can have its contents changed to point to some other location, whereas the alias last cannot be changed within the scope of these declarations. Notice that while both pointer p and reference declaration last both allow you to get at a specific data element, the pointer p itself can be changed so that it can look at other elements of the array; for example, p can also be set to look at the third element of the array by using the statement


p = &data[2];

In contrast, the reference declaration last provides an alias or additional name for the array element data[2] . By definition, variables delcared with the type& form cannot be modified. They are constant pointers. Thus, the variable last cannot be changed and will always point at the array element data[2] , though the contents of data[2] can be changed.

Let's use this in the context of class members. We will have return types that are rvalue types, and return types that are lvalue types. In the following example, in the member function double& x_lv() the return type is an lvalue, so return x must return the location of x . In the member function double get_x() the return type is a double , so return x uses the rvalue which is copied back as the value of this function.


#include < iostream >
#include < string >
using namespace std;

class point {
public:
   point(double x_in = 0.0, double y_in = 0.0): x(x_in), y(y_in {}
   double get_x() { return x;} //returns the rvalue of x
   double get_y() { return y;}
   double& x_lv() { return x;} //returns an alias to x
   double& y_lv() { return y;}
private:
   double x, y;
};

int main()
{
   point a(2.5, -2.5), b(1.0, 1.0), c;

   cout << "lvalue-rvalue semantics\n";
   //compute the midpoint
   c.x_lv() = (a.get_x() + b.get_x()) / 2;
   c.y_lv() = (a.get_y() + b.get_y()) / 2;
   //notice you get the same output because
   //an lvalue is automatically dereferenced where
   //appropriate to give the rvalue
   cout << c.get_x() << ", " << c.get_y() << endl;
   cout << c.x_lv() << ", " << c.y_lv() << endl;
}