Understanding lvalues and rvalues in C++ (Part 01)

Sanduni Galagoda
2 min readMay 2, 2021

Introduction

rvalue references are a feature introduced to C++, since C++ 11 standard came in to practice. The rvalue reference concept is a bit difficult to grasp for a novice C++ programmer and it might not be clear as to what problems it solves.

At a high level rvalue references solve at least two problems.

  1. Implementing Move Semantics
  2. Perfect Forwarding

Now don’t you panic, seeing this terms. Let’s see what these unfold into… :)

Move Semantics

A simple definition for lvalues and rvalues could be: An lvalue is an expression that refers to a memory location and allows us to take the address of that memory location via the & operator. An rvalue is an expression that is not an lvalue. Although this definition is arguable, still it gives us a good idea. Let’s look at a simple example,

//lvalue examples
int a = 60;
a = 52;
int* ptr_int = &a;
//a is an lvalue in all above instances

//rvalue examples
int ExampleFunction();
int b = 0;
b = 60; // here 60 is an rvalue
b = ExampleFunction(); // ExampleFunction() is also an rvalue
int* ptr_int = &ExampleFunction(); //This would give an error since you can not take address of a rvalue

Consider a situation where Y is a class which has a pointer to a resource as a member variable. Think of this resource as an object which has allocated memory. The copy assignment operator of Y would do the following (Suppose right hand side of the assignment operator has variable RHS. RHS.resource is the pointer to the resource.),

  1. Make a clone of what RHS.resource points to.
  2. Destruct the resource which Y points to.
  3. Attach the clone to Y.resource.

A similar logic applies to the copy constructor as well.

Consider the following scenario,

Y CreateInstanceOfY();
Y y;
y = CreateInstanceOfY();

The assignment in the last line does the following,

  1. Temporary object returned by CreateInstanceOfY() is cloned.
  2. Resource held by y is destructed and replaced with the clone.
  3. the temporary object is destructed and it’s memory is freed.

So another obvious approach to do this efficiently would be to swap the resource pointers between y and the temporary object and let the temporary object’s destructor free the memory pointed by y.resource originally. This is an instance where the right hand side of the assignment operator has a rvalue and we want the copy assignment operator to work this way: swap Y.resource and RHS.resource pointers. This is called Move Semantics.

In C++ 11 this conditional behaviour can be obtained by overloading the copy assignment operator by using an rvalue reference.

EX:

Y& Y::operator=(Y&& RHS){
//exchange the content between this and RHS: This is Move Semantics
return *this;
}

Let’s look at more about rvalue references and perfect forwarding in the upcoming article…

References: http://thbecker.net/articles/rvalue_references/section_01.html

--

--