What are lvalues and rvalues
Recently I came across the concepts of lvalues and rvalues. Conceptually, I have understood these concepts to be as follows:
lvalues are those values which have an address.
rvalues are temporary values that are not associated with any particular object.
Why these concepts are useful?
This topic is important for efficiency. Often copying data is a costly operation, and it can be advantageous to "move" the data instead.
A simple example showing a copy and move constructor illustrates this point.
Consider the source code below:
/* original constructor */
Matrix(int rows, int cols) : rows(rows), cols(cols), size(rows * cols)
std::cout << "original constructor" << std::endl;
data = new double[size];
/* copy constructor */
Matrix(const Matrix &rhs) : rows(rhs.rows), cols(rhs.cols), size(rhs.rows * rhs.cols), data(new double[size])
std::cout << "copy constructor" << std::endl;
std::copy(rhs.data, rhs.data + size, data);
/* move constructor */
Matrix(Matrix &&rhs) : rows(rhs.rows), cols(rhs.cols), size(rhs.rows * rhs.cols), data(rhs.data)
std::cout << "move constructor" << std::endl;
rhs.rows = 0;
rhs.cols = 0;
rhs.size = 0;
rhs.data = nullptr;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
std::cout << data[i * cols + j] << "\t";
std::cout << std::endl;
/* create a new matrix on the heap */
Matrix *my_matrix = new Matrix(10, 10);
/* give it some interesting cell values */
for (int i = 0; i < my_matrix->size; i++)
my_matrix->data[i] = i;
/* Now we can try and see the difference between the move and copy semantics */
/* std::move casts to a rvalue pointer, which in turn means the move constructor in the class is invoked */
/* clear the memory */
/* check the copy constructed matrix values */
std::cout << "copied constructed matrix" << std::endl;
/* check the move constructed matrix values */
std::cout << "moved constructed matrix" << std::endl;
In this code I create a very simple
Matrix class. For simplicity it doesn't do much.
Matrix class there are three different constructors;
To invoke the
move constructor, we need to just do the following steps:
moveconstructor takes in an rvalue referrence as a parameter. This is done by using
&&in the parameter list.
We need to make sure we pass in an rvalue reference to the constructor. This is done by using
std::movein the main function.
std::movecasts it's argument to an rvalue. This ensures that the correct constructor is called.
Once these two steps are fulfilled, the move constructor will be invoked.
After we call
std::move the new matrix has ownership of the data. For this reason it is important to fix any wayward pointers
in the move constructor body.