C++11 Move Contsructor & rvalue References

In this article we will discuss the use of rvalue references in C++11 move semantics.

Problem of Temporary Objects

The Idea behind this move semantics is to reduce the load of these temporary objects on memory. Every time we return a object from a function then a temporary object is created, which eventually get copied. In then end we create 2 copies of an object whereas, we need only one. Let’s understand by an example,

Suppose we have a Container class that contains a integer pointer as member variable,

class Container < int * m_Data; public: Container() < //Allocate an array of 20 int on heap m_Data = new int[20]; std::cout ~Container() < if (m_Data) < delete[] m_Data; m_Data = NULL; >> Container(const Container & obj) < //Allocate an array of 20 int on heap m_Data = new int[20]; //Copy the data from passed object for (int i = 0; i < 20; i++) m_Data[i] = obj.m_Data[i]; std::cout >;

When we create an object of Container class, then its default constructor internally allocates an array of 20 int on heap and assign it to its member variable.

Similarly, Container class’s copy constructor allocates an array of 20 int on heap, then copy the contents of passed objects array into it and then assign it to its member variable.

Generally, we use Factory classes to create object of our classes. On similar lines, let’s create a simple function that creates an object of Class Container and returns i.e.

Frequently Asked:

// Create am object of Container and return Container getContainer()

Now in main function we created a vector of Container type and inserted an object returned by getContainer() function i.e.

int main() < // Create a vector of Container Type std::vectorvecOfContainers; //Add object returned by function into the vector vecOfContainers.push_back(getContainer()); return 0; >

Now, at last there is one object in the vector vecOfContainers. But we actually created 2 objects for it because getContainer() function returned a temporary object which got copied into a new object and then destructed. This 2nd object got inserted in vector. So, 2 objects of class Container are created at following step in above code,

To create each of these 2 objects it allocated an array of 20 int on heap 2 times and at last only one was used. So, its clearly a wastage of resources and effort.

How to solve this problem of resource and effort wastage due to temporary objects? Is there a way to move the 1st object instead of creating 2nd one and copying contents to it?

Answer is yes. This is where move semantics and rvalue references comes into picture.

Solving Problem of Temporary Objects using rvalue references & Move Constructor

The getContainer() function here is a rvalue, so it can be referred by a rvalue reference. Also, using rvalue reference we can also overload functions. This time, we will overload the Constructor of class Container and this new Constructor will be called move constructor.

Move Constructor

Move constructor takes a rvalue reference as an argument and that makes it overloaded because Copy Constructor takes the const lvalue reference as an argument. In Move constructor we just move the member variables of passed object into the new object’s member variables, instead of allocating new memory for them.

Let’s see the move constructor for class Container i.e.

Container(Container && obj) < // Just copy the pointer m_Data = obj.m_Data; // Set the passed object's member to NULL obj.m_Data = NULL; std::cout

In the move constructor, we just copied the pointer. Now member variable m_Data points to the same memory on heap. Then we set the m_Data of passed object to NULL. So, we didn’t allocated any memory on heap in move constructor, we just shifted the control of memory.

Now if we create the vector of class container and push a object returned from getContainer() into it. Then a new object will created from this temporary object but as getContainer() is a rvalue, so Move Constructor of this new Container class’s object will be called and in that memory will be just shifted. So, actually on heap we will create only one array of integers.

Similar to Move Constructor we can have Move Assignment operator that will just shift the content. Checkout the complete example as follows,

#include #include class Container < int * m_Data; public: Container() < //Allocate an array of 20 int on heap m_Data = new int[20]; std::cout ~Container() < if (m_Data) < delete[] m_Data; m_Data = NULL; >> //Copy Constructor Container(const Container & obj) < //Allocate an array of 20 int on heap m_Data = new int[20]; //Copy the data from passed object for (int i = 0; i < 20; i++) m_Data[i] = obj.m_Data[i]; std::cout //Assignment Operator Container & operator=(const Container & obj) < if(this != &obj) < //Allocate an array of 20 int on heap m_Data = new int[20]; //Copy the data from passed object for (int i = 0; i < 20; i++) m_Data[i] = obj.m_Data[i]; std::cout > // Move Constructor Container(Container && obj) < // Just copy the pointer m_Data = obj.m_Data; // Set the passed object's member to NULL obj.m_Data = NULL; std::cout// Move Assignment Operator Container& operator=(Container && obj) < if(this != &obj) < // Just copy the pointer m_Data = obj.m_Data; // Set the passed object's member to NULL obj.m_Data = NULL; std::cout> >; // Create am object of Container and return Container getContainer() < Container obj; return obj; >int main() < // Create a vector of Container Type std::vectorvecOfContainers; //Add object returned by function into the vector vecOfContainers.push_back(getContainer()); Container obj; obj = getContainer(); return 0; >

Output:

Constructor: Allocation 20 int Move Constructor Constructor: Allocation 20 int Constructor: Allocation 20 int Move Assignment Operator

In the above example, Move constructor of class Container will be called because getContainer() returns a rvalue and Container class has a overloaded version of Constructor that accepts rvalue in rvalue reference. Inside this Move constructor memory is just shifted.

Similarly in following lines,

Container obj; obj = getContainer(); // Move Assignment will be called

Move Assignment Operator was called instead of assignment operator and memory just got shifted.

Related posts:

  1. What is rvalue reference in C++11
  2. Difference between lvalue and rvalue in C++
  3. Is rvalue immutable in C++?
  4. Different ways to insert elements in an unordered_map
  5. How to Erase / Remove an element from an unordered_map
  6. c++11 unordered_map : erase elements while iterating in a loop
  7. multimap Example and Tutorial in C++
  8. std::initializer_list Tutorial & Examples | C++11
  9. Using std::initializer_list in constructors to initialize member variables
  10. C++ : How to Initialize a map in one line using initialzer_list ?
  11. Variadic Templates in Modern C++
  12. C++11 : Start thread by member function with arguments
  13. How to put a thread to sleep in c++11 ? | sleep_for | sleep_until
  14. C++11 Multithreading – Part 9: std::async Tutorial & Example
  15. How to Capture Member Variables in Lambda function in C++?
  16. C++11 Lambda: Capture Variables by Reference or Value
  17. C++11 Multithreading – Part 10: packaged_task<> Example and Tutorial
  18. What is unique_ptr in C++?
  19. C++11 : std::tuple Tutorial & Examples
  20. C++11 : make_tuple Tutorial & Example