Because of copy elision. In short, C++ implementations are allowed to not call copy/move constructors for objects when they'd be initialized from some nameless temporary of the same type. This happens even if those constructors have side effects.
This is desirable behavior for many, many circumstances, but there are cases where you might want to turn it off. The way to do so, AFAIK, varies with compiler. For g++ and clang++, I believe the flag is -fno-elide-constructors. There are also probably attributes and pragmas to do so as well. Doing that will get you the following output:
Mh, so I wonder why (with the flag) the destructor of the temporary object will be called. I thought that the move constructor moves the content of a temporary to the newly created object. But if the temporary's data will get destroyed, that's bad.
The move constructor does not make the moved-from object cease to exist. It needs to leave that object in a valid state. What that state is, the standard doesn't say, but it should be destroyable in a way that makes sense.
And yes, you do presently have a problem with your move constructor. :D
Yep, assuming that nullptr is a valid value for your data member variable (by your own designs).
What I mean by that is that... well, if you have any functions that blindly assume that data points to an array of 3 ints, then those functions are going to be in for a rude surprise.
>... well, if you have any functions that blindly assume that data points to an array of 3 ints, then those functions are going to be in for a rude surprise.
That should never happen, because the move-constructor will then and only then be invoked if X other is an r-value and thus nevermore could get used after passing to the move constructor.
The point is that it's a not-uncommon circumstance under which a move constructor would be called, and the moved-from object doesn't expire immediately after. It's something to consider, especially if your code is going to be reviewed/used by other people.
Whoops, I typed without really thinking about the details of what I was typing. You're right. X some_x = std::move(another_x); would be a different story, though.