'What happens internally when std::move is called?

I wanted to know what exactly happens internally when we call std::move on an object. For example:

class Holder {
    int* m_ptr;
    int m_size;
public:
    Holder(int size) : m_size(size),
        m_ptr(size ? new int[size] : 0) {
        cout << "Constructor\n";
    }
    ~Holder() {
        cout << "Destructor\n";
        delete[] m_ptr;
    }

    Holder(const Holder& other) {
        cout << "Copy Constructor\n";
        m_ptr = new int[other.m_size];
        std::copy(other.m_ptr, other.m_ptr + other.m_size, m_ptr);
        m_size = other.m_size;
    }

    void swap(Holder& other) noexcept {
        std::swap(this->m_ptr, other.m_ptr);
        std::swap(this->m_size, other.m_size);
    }

    Holder& operator=(const Holder& other) {
        cout << "Copy Assignment\n";
        Holder(other).swap(*this);
    }

    Holder(Holder&& other) : m_ptr(other.m_ptr), m_size(other.m_size) {
        cout << "Move Constructor\n";
        other.m_ptr = nullptr;
        other.m_size = 0;
    }

    Holder& operator=(Holder&& that) noexcept {
        cout << "Move Assignment\n";
        Holder(std::move(that)).swap(*this);
        return *this;
    }
};


Holder createHolder(int size) {
    return Holder(size);
}

int main(void) {
    Holder h = createHolder(1000);
    return 0;
}

Gives the output as when compiled with '-fno-elide-constructors':

Constructor
Move Constructor
Destructor
Move Constructor
Destructor
Destructor

Since we are returning from a function createHolder and the return object is on the stack, how does the main function still receives it? Not getting exactly what happens internally in memory.

Thanks.



Solution 1:[1]

std::move is a noop function that converts any kind of reference into an rvalue reference. So it doesn't actually "do" anything, it just changes how it's argument is used.

template <class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;
    Returns: static_cast<remove_reference_t<T>&&>(t).

Solution 2:[2]

std::move make your operator =, constructor is call correctly with what you defined in the Holder class

Holder(Holder&& other) : m_ptr(other.m_ptr), m_size(other.m_size) {
    cout << "Move Constructor\n";
    other.m_ptr = nullptr;
    other.m_size = 0;
}

Holder& operator=(Holder&& that) noexcept {
    cout << "Move Assignment\n";
    Holder(std::move(that)).swap(*this);
    return *this;
}

Since we are returning from a function createHolder and the return object is on the stack, how does the main function still receives it? because your move constructor

you already copy pointer m_ptr(other.m_ptr) m_size(other.m_size) from Holder(size) -> move to Holder object in return register on stack -> move to Holder h in main function

Constructor  -> of Holder(size);
Move Constructor -> Holder(size) move to Holder object in return register on stack
Destructor -> destructor of Holder(size)
Move Constructor -> from Holder object on stack -> Holder h in main
Destructor -> destructor of Holder object in return register
Destructor -> destructor of Holder h in main

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chris Dodd
Solution 2