top of page

Move constructor in c++.


rvalue Reference:

rvalue references can do what lvalue references fails to do i.e. a rvalue reference can refer to rvalues.

Declaring rvalue reference

To declare a rvalue reference, we need to specify two & operator i.e. &&.

int a = x+1;

int &lvalueRef = a; //lvalueRef is lvalue reference.

int && rvalueRef = (x+1); // rvalueRef is rvalue reference


What was the need of rvalue references in C++11 ?

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<<"Move Constructor"<<std::endl;
}

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 <iostream>
#include <vector>

class Container {
 int * m_Data;
public:
 Container() {
  //Allocate an array of 20 int on heap
        m_Data = new int[20];

        std::cout << "Constructor: Allocation 20 int" << std::endl;
 }
    ~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 << "Copy Constructor: Allocation 20 int" << std::endl;
 }

  //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 << "Assigment Operator: Allocation 20 int" << std::endl;
 }
 }

  // 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 Constructor"<<std::endl;
 }

  // 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<<"Move Assignment Operator"<<std::endl;
 }
 }

};

// Create am object of Container and return
Container getContainer()
{
    Container obj;
 return obj;
}
int main() {
  // Create a vector of Container Type
    std::vector<Container> vecOfContainers;

  //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.

Comments


bottom of page