C++

C++ Move Constructor

C++ programming is the best language as it facilitates us with a wide range of functions, constructors, header files, classes, and much more, making coding more interesting and easier. One of the constructors in C++ programming is the “move” constructor. The “move” constructor is a unique kind of constructor that allows ownership of a dynamically allocated memory or other resources to be transferred from one object to another in an effective and resource-conscious manner.

In C++ programming, “move” constructors were introduced to reduce the duplication and enhance the efficiency. It plays a crucial role in improving the performance by minimizing the copying operations. This guide deeply explores about the “move” constructor in C++ programming.

Example 1:

To begin the code here, we include the “iostream” and “string” header files that will make our code run perfectly since many functions are declared in these header files. When we have to utilize the “cout” statement, the “iostream” header file is utilized since this function is declared inside this. When we have to work with the string type data, the “string” header file is necessary.

After this, the “namespace std” is added below these header files. Then, we construct a class here. The class name is “Move”. Below this, the “private” keyword is added in which we declare a private string variable with the “my_str” name. Now, we place the “public” keyword where we add the definition of the default constructor. We pass “This is the default string here” to the “my_str” as the parameter and leave the default constructor empty.

After this, we copy the constructor definition and initialize “my_str” to “my_obj.my_str”. Below this, we print a line and then place the definition of the “move” constructor. Here, we initialize “my_str” again with “my_obj.my_str”. We don’t add any statement below this; it is empty. After this, we declare a function named “displayMyObject()” of string type and utilize the “return str” so it returns the string.

We place the global “new_temp” function in the “move” type. Below it, we have the “return temp” which returns the move type object. Now, we place the “main()” driver code and the “new_obj1” of the “move” type and get the “move” constructor from the “rvalue”. In the line ahead, we place the “new_obj1.displayMyObject()” to get the “move” constructor from the “lvalue”. After this, we call the “move” constructor with the “my_obj1” object. Then, we transfer the ownership of the “my_obj1” to the other object which is “my_obj2”.

Code 1:

#include <iostream>

#include <string>

using namespace std;

class Move

{

private:
    string my_str;
public:
    Move() : my_str("This is the default string here")
    {
    }
    Move(const Move &my_obj) : my_str(my_obj.my_str)  
    {


        cout << "Copy constructor invoked, Move failed!\n";

    }
    Move(Move &&my_obj) : my_str(move(my_obj.my_str))  
    {
    }
    string displayMyObject()  
    {
        return my_str;
    }
};
Move new_temp(Move tmp)
{
    return tmp;
}
int main()
{
    Move new_obj1 = new_temp(Move());        


    cout << "before move() call : new_obj1 = " << new_obj1.displayMyObject() << endl;

    Move new_obj2 = move(new_obj1);

    cout << "after move() constructor call : new_obj1 = " << new_obj1.displayMyObject() << endl;

    cout << "after move() constructor call : new_obj2 = " << new_obj2.displayMyObject() << endl;

    return 0;

}

Output:

The output renders that before calling the “move()” method, the “new_obj1” contains the default string. But after calling the “Move” class move() method, “my_obj1” contains an empty string and “my_obj2” has the default string.

Example 2:

Here, we include one more header file which is the “vector” header file. We include this whenever we have to manipulate the operations on the vectors. The class that we create here is the “Move” class. We also create a “public” constructor here in which we declare the “int* value” raw pointer to be a class member’s data. Below it, we have the “public” in which we place the “Move” constructor and pass “int v1” as its parameter.

After this, we declare the objects in a heap. We initialize the “value” with “new int” and the “*value” with “v1”. Then, place the “cout” where we add a line that prints when we execute the code. Below this, we utilize the “copy” constructor. This “copy” constructor copies the data by making a deep copy. We place the “Move” constructor and pass “Move&& new_source” as its parameter. Below it, we place the “cout” which aids in displaying the required statement.

We insert the “nullptr” keyword to determine whether a pointer is empty before the reference is utilized. Now, we also place the “~Move()” destructor in which we place the “if” condition which verifies whether the “value” is not equal to “nullptr”. When this condition is verified, the statement below this is executed. If this condition is not verified, it skips the “cout” statement which is present after the “if” condition and moves towards the “else” part.

After this, we utilize the “delete” keyword which aids in deallocating an object or we can say that it releases the memory that is allocated to the object’s data component. Now, we invoke the “main()” method here and create the vector of our “Move” class with the name, “my_vec”. After this, we utilize the “push_back()” function that helps to insert a value at a vector’s endpoint. The “vector” header file contains this function. First, we insert “39” into the vector. Then, “57” is inserted and “91” is also inserted by utilizing the “push_back()” method.

Code 2:

#include <iostream>

#include <vector>

using namespace std;

class Move {

private:
    int* value;
public:
    Move(int v1)
    {
        value = new int;
        *value = v1;

        cout << "The Constructor is called for "

                << v1 << endl;

    };
    Move(const Move& new_source)
        : Move{ *new_source.value }
    {


        cout << "Copy Constructor is called -"

                << "Deep copy for "

                << *new_source.value

                << endl;

    }
    Move(Move&& new_source)
        : value{ new_source.value }
    {


        cout << "Move Constructor for "

                << *new_source.value << endl;

        new_source.value = nullptr;

    }
    ~Move()
    {
        if (value != nullptr)


            cout << "Destructor is called for "

                        << *value << endl;

        else

            cout << "Destructor is called"

                        << " for nullptr "

                        << endl;

        delete value;

    }

};

int main()

{

    vector<Move> my_vec;

    my_vec.push_back(Move{ 39 });
    my_vec.push_back(Move{ 57 });
    my_vec.push_back(Move{ 91 });
    return 0;


}

Output:

This shows that instead of using the “copy” function, we have to utilize the “move” function to prevent the needless call to the “copy” function. The “move” constructor is invoked here when we initialize the object with a temporary object or some object that will be destroyed. Instead of manipulating a deep copy of the given data, the “move” constructor shifts the ownership of the resources from one object to another.

Conclusion

In this guide, we explored about the “move” constructor. We explained that the “move” constructor in C++ programming is a unique method to relocate an object’s resources to another object effectively. We discussed that calling the “move” constructor has less overhead, making the code more memory-efficient. We explored the fact that the “move” constructor is a powerful feature in C++ programming. We also utilized the practical examples to illustrate the concept of the “move” constructor and demonstrated the performance benefits of utilizing the “move” constructor in C++ programming.

About the author

Omar Farooq

Hello Readers, I am Omar and I have been writing technical articles from last decade. You can check out my writing pieces.