26
struct copyable { // and movable
  copyable() = default;
  copyable(copyable const&) { /*...*/ };
  copyable& operator=(copyable const&) { /*...*/ return *this; }
};

Since the copy constructor and copy assignment operation functions are explicitly defined, it signifies that the move constructor and move assignment function cannot be implicitly defined by the compiler and hence the move operation is not allowed.

Can you please let me know whether my above understanding is correct?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Balan K
  • 356
  • 2
  • 11
  • 3
    Moving can be seen as a special case where the original variable need not be preserved. Preserving the original variable (like copying) does not invalidate the move. – Bernard Jun 21 '17 at 09:17
  • related/dupe: https://stackoverflow.com/questions/33939644/understanding-stdis-move-constructible – NathanOliver Jun 21 '17 at 13:05
  • 1
    To add a bit more detail to Bernard's comment: After a move, the source variable is not guaranteed to be empty. (Some objects may not even have the concept of "empty".) It *can* be empty, of course, or it could be unchanged, or it could be something else entirely e.g. it could now have the value that was previously in the target variable (in the case of assignment). In the case of std::string, it is often empty if it was a long string before the move, and unchanged if it was a short string. – Arthur Tacca Jun 21 '17 at 13:05

1 Answers1

31

it signifies that move constructor and move assignment function cannot be implicitly defined by the compiler

Yes that's right.

and hence move operation is not allowed.

No, move operations can still be performed via the copy constructor and copy assignment operator (though this may not be the case you expected), because an rvalue could always be bound to const&.

More precisely, class copyable is still MoveConstructible and MoveAssignable .

A class does not have to implement a move constructor to satisfy this type requirement: a copy constructor that takes a const T& argument can bind rvalue expressions.

If a MoveConstructible class implements a move constructor, it may also implement move semantics to take advantage of the fact that the value of rv after construction is unspecified.

and

The type does not have to implement move assignment operator in order to satisfy this type requirement: a copy assignment operator that takes its parameter by value or as a const Type&, will bind to rvalue argument.

If a MoveAssignable class implements a move assignment operator, it may also implement move semantics to take advantage of the fact that the value of rv after assignment is unspecified.

As @Curious pointed, you can declare the move constructor and move assignment operator delete explicitly to make copyable unmovable; then using with an rvalue expression the deleteed overload will be selected and compile would fail.

Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 5
    I think it's worth mentioning how explicitly deleting the move constructor and assignment operator would change things – Curious Jun 21 '17 at 09:23
  • 2
    @Curious Added. – songyuanyao Jun 21 '17 at 09:28
  • 4
    But deleted move members combined with non-deleted copy members is nearly always a logical error, as then the class fails to meet the `CopyConstructible` and `CopyAssignable` requirements (which require copying from rvalues). This will, for example, disallow returning a local lvalue from a factory function by value. Guideline: Never delete the move members: https://stackoverflow.com/a/38820178/576911 – Howard Hinnant Jun 21 '17 at 15:54