Ivaylo Valchev
Ivaylo Valchev

Reputation: 10415

"Defaulted" move constructor and assignment - weird behaviour

So I have a simple example of a class which has two member variables. And I've declared a copy and a move constructor which are = default, which would force the compiler to generate them for me. Now my question is this. When the move constructor (or assignment) is used, why does the object from which I've moved stay intact?

For example if I have:

myclass obj(4, 5);
myclass obj2 = std::move(4, 5);

As I understand it, after the second line obj will contain "nothing", as it will have been moved into obj2 which will have the values (4, 5). I know I'm not using to correct terms here....

Full code:

#include <iostream>
#include <utility>

template<class T1, class T2>
class Pair
{
public:
    T1 first;
    T2 second;

public:
    //CONSTRUCTORS
    constexpr Pair() = default;

    constexpr Pair(const T1& _first, const T2& _second)
        : first(_first), second(_second)
    {}

    constexpr Pair(T1&& _first, T2&& _second)
        : first(std::forward<T1>(_first)), second(std::forward<T2>(_second))
    {}

    constexpr Pair(const Pair&) = default;
    constexpr Pair(Pair&&)      = default;

    //ASSIGNMENT
    Pair &operator=(const Pair&) = default;
    Pair &operator=(Pair&&)      = default;
};

int main()
{
    Pair<int, int> p(1, 2);

    Pair<int, int> p2 = p; //all good, p = {1, 2} and p2 = {1, 2}

    Pair<int, int> p3 = std::move(p); //p = {1, 2} and p3 = {1, 2}
                                    //why isn't p "moved" into p3??
                                    //p should be empty??

    //same thing occurs with the move assignment. why?

    std::cout << p.first << " " << p.second << "\n";
    std::cout << p2.first << " " << p2.second << "\n";
    std::cout << p3.first << " " << p3.second << "\n";
}

Live example: http://coliru.stacked-crooked.com/a/82d85da23eb44e66

Upvotes: 1

Views: 97

Answers (2)

Guillaume Racicot
Guillaume Racicot

Reputation: 41750

The default move constructor and move assignement will simply call std::move to all members. Just like the copy, the default copy constructor simple call the copy of all members.

Your code is correct, and after calling std::move, it's normal the moved data still exist. Why? Because std::move on primitive copies them. The compiler will not produce code to make moved int to 0, so it's a simple copy. However, if you pair contains a more complex type such as a std::vector<int>, the moved vector will effectively end up empty.

Upvotes: 2

Jarod42
Jarod42

Reputation: 217085

Default move for int is just a copy.

Upvotes: 3

Related Questions