0

I am trying to learn Move Constructors but I am unable to understand them after watching multiple videos. Please help with the following questions :

  1. When pushing back temporary objects using Vectors, does the compiler first create the object and then copy it to the vector ?
  2. Why do we need to need to null out the pointer in source object in Move Constructor ?
  3. If I write vector_name.push_back(Class_Name{10}); , what does the "10" mean here?
LykanMD
  • 13
  • 4
  • `Class_name{10}` *could* be the same as `Class_name(10)`, i.e. it constructs a (temporary) object of the type `Class_name` and pass the `int` value `10` to its constructor. Note that this is really a completely different issue than the rest of your question. And should be answered in any decent book or tutorial or class. – Some programmer dude Jul 20 '20 at 11:08
  • Ask one question in one post at a time. Mostly only one question is answered in one post and other seemed lost later on. welcome to SO! please read [mcve] – Dev Jul 20 '20 at 11:24
  • Maybe a [good C++ book](https://stackoverflow.com/a/388282/4641116) would be better than videos. For 1, there's std::vector [push_back](https://en.cppreference.com/w/cpp/container/vector/push_back) and there's [emplace_back])(https://en.cppreference.com/w/cpp/container/vector/emplace_back). For 2, it does not *need* to null out the pointer, it just needs to track its state for the destructor or assignment operator; nulling out the pointer is one way to do it. [mcve] showcasing your confusion would be helpful. – Eljay Jul 20 '20 at 11:29

1 Answers1

1

Move semantic is not a copy of something. Actually, you steal their resources. For example, you have created an object, let's say A, that is going to initialized with an object, let's say B. How could happen this case? You can either copy their values or steal their resources. If you do not use B object anymore, I mean its life is done, you can steel its resource. It is move semantic. But if you going to use B object you can copy its values. It is a copy semantic.

#include <iostream>
#include <cstdlib>


class Data {
private:
    int* mptr;
    size_t mlen;
public:
    Data(const int* p, size_t len) : mptr{ static_cast<int*>(std::malloc(sizeof(int) * len)) }, mlen(len) // constructor
    {
        for (size_t i = 0; i < len; ++i)
        {
            mptr[i] = p[i];
        }
    }
    ~Data() // deconstructor
    {
        std::free(mptr);
    }
    Data(const Data& other) : mptr{ static_cast<int*>(std::malloc(sizeof(int) * other.mlen)) }, mlen(other.mlen) // copy constructor
    {
        for (size_t i = 0; i < other.mlen; ++i)
        {
            mptr[i] = other.mptr[i];
        }
    }
    Data(Data&& other) : mptr{ other.mptr }, mlen(other.mlen) // move constructor
    {
        other.mptr = nullptr;
    }
    Data& operator=(const Data& other) // copy assignment
    {
        if (this != &other)
        {
            std::free(mptr);
            mptr = static_cast<int*>(std::malloc(sizeof(int) * other.mlen));
            for (int i = 0; i < other.mlen; ++i)
            {
                mptr[i] = other.mptr[i];
            }
            mlen = other.mlen;
        }
        return *this;
    }
    Data& operator=(Data&& other) // move assignment
    {
        if (this != &other)
        {
            std::free(mptr);
            mptr = other.mptr;
            mlen = other.mlen;
            other.mptr = nullptr;
        }
        return *this;
    }

    void print()const
    {
        for (size_t i = 0; i < mlen; ++i)
        {
            std::cout << mptr[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main()
{
    int arr1[5] = { 1,2,3,4,5 };
    int arr2[4] = { 10,11,12,13 };
    Data d1{ &arr1[0],5 }; // constructor called
    d1.print(); // 1 2 3 4 5

    Data d2 = d1; // copy constructor called
    d2.print(); // 1 2 3 4 5

    Data d3{ Data{&arr2[0],4} }; // move ctor called, temporary object
    d3.print(); // 10 11 12 13

    d3 = std::move(d2); // move assignment called
    d3.print(); // 1 2 3 4 5
    //d2.print(); // error because d2.mptr = nullptr

    d2 = d1; // copy assignment called
    d1.print(); // 1 2 3 4 5
    d2.print(); // 1 2 3 4 5
    
}

In the above code, I have implemented constructor, destructor, copy constructor, copy assignment, move constructor, and move assignment. As I mentioned earlier if I call move semantic. It means I will not use the object anymore.

d1 created via the constructor. d2 created with a copy constructor. It means d2 has the same value as d1 but different memory addresses. When I delete d1, it deletes only its own resources.

But d3 created via move constructor. Because using Data{&arr2[0],4} this code, compiler creates a temporary object then d3 steal its resources. That temporary object will die end of the line. So that there is no reason to use copy semantic. It will use unnecessary resources.

After that, d3 steals d2 resources via move assignment. After this code, d3 = std::move(d2), execution d2 has no resource. It means if you call the print function it will throw an error like d2.print(). Then d2 again take a resource via copy assignment. mptr of d1 and d2 are completely different.

Why we have assign mptr as a nullptr? Because if you do not assign it when the destructor called it will be freed. So that it will create an error.

Also, 10 is an initial value.

Murat Hepeyiler
  • 430
  • 3
  • 12
  • Thank you for your time and efforts. I am a beginner (noob) so some of your code is difficult for me to understand. But your explanation clarified a lot of things for me. So Thank you very much. I have upvoted your solution but but I can not accept it as an answer as your code is too complicated for me to understand perfectly. I sincerely apologize for that. – LykanMD Jul 20 '20 at 13:23