1

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

DeiDei
  • 10,205
  • 6
  • 55
  • 80
  • 2
    How would it contain "nothing"? How do you make an `int` store "nothing"? You could copy it then set it to `0` but that would be _more_ work than just copying it, and moving is meant to be at least as efficient as copying, so it would be dumb if the compiler "moved" simple values by doing extra work. – Jonathan Wakely Nov 25 '15 at 15:28

2 Answers2

3

Default move for int is just a copy.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

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.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • A moved-from `vector` is in a valid but unspecified state. It's not necessarily empty. – T.C. Nov 26 '15 at 07:01