2

I didn't understand this in C++ primer 5 ed. :

For example, assuming Y is a class that defines its own copy constructor but does not also define its own move constructor:

// assume Y is a class that defines its own copy constructor but not a move constructor

struct hasY { hasY() = default; hasY(hasY&&) = default; Y mem; // hasY will have a deleted move constructor }; hasY hy, hy2 = std::move(hy); // error: move constructor is deleted

The compiler can copy objects of type Y but cannot move them. Class hasY explicitly requested a move constructor, which the compiler is unable to generate. Hence, hasY will get a deleted move constructor. Had hasY omitted the declaration of its move constructor, then the compiler would not synthesize the hasY move constructor at all. The move operations are not synthesized if they would otherwise be defined as deleted.

So I've defined Y as he said:

struct Y
{
    Y() = default;
    Y(const Y&){std::cout << "Y's Copy-ctor\n";
    Y& operator=(const Y&){std::cout << "Y's copy-assignment operator\n"; return *this;}

};

struct hasY {
    hasY() = default;
    hasY(hasY&&) noexcept = default;
    Y mem; // hasY will have a deleted move constructor
};

In main:

 hasY hy, hy2 = std::move(hy); // error: move constructor is deleted
  • But the program works fine and doesn't complain about a deleted move constructor as he said?!

The output:

Y's copy ctor
  • As you can see the program runs fine with me although I've tested it on many compilers with different versions and with different compiling flags. I guess it is a mistake in the book.

  • I think class hasY is moveable and its move constructor is not deleted because that move-ctor calls move ctor of class Y which is implicitly not defined (not deleted but not defined) so it falls to use Y's copy-ctor So I think class Y is moveable through its copy constructor. Thus the program pints Y's copy-ctor.

** In cppreference it is said:

The implicitly-declared or defaulted move constructor for class T is defined as deleted if any of the following is true:

T has non-static data members that cannot be moved (have deleted, inaccessible, or ambiguous move constructors); T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors); T has direct or virtual base class with a deleted or inaccessible destructor;

T is a union-like class and has a variant member with non-trivial move constructor;

T has a non-static data member or a direct or virtual base without a move constructor that is not trivially copyable.

The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).

  • I also have an ambiguity between: "implicitly defined as deleted operation" and "not defined at all"? To me defined as deleted is as if writing:

    Y(Y&&) = delete; // generated by the compiler
    

And not defined at all is the same meaning of the expression.

*** To confirm my saying that class hasY's move constructor is not deleted then here is just a simple:

struct hasY {
    hasY() = default;
    hasY(hasY&&) noexcept = default;
    Y mem; // hasY will have a deleted move constructor
    std::unique_ptr<int> upi; // This really causes hasY non-copy-able
};
  • As you can see I've added a non-copy-able object of type uniqe_ptr to prevent the copy of hasY and the program runs as before with no erorrs which means hasY's move constructor is not deleted.
Maestro
  • 2,512
  • 9
  • 24
  • `hasY` does not have a move constructor, but it **does** have a copy constructor, so the compiler makes a copy of the object rather than moving it. – Raymond Chen Feb 08 '20 at 19:46
  • @RaymondChen: Are you sure? – Maestro Feb 08 '20 at 19:46
  • Sorry, misread. I thought there was a `hasY(hasY const&) = default;` but there wasn't. This doesn't compile on [godbolt](https://gcc.godbolt.org/z/izWJmQ). – Raymond Chen Feb 08 '20 at 19:51
  • @RaymondChen: Now I've edited the code (last paragraph): Adding a unique_ptr means this class has no copy control operations thus the program works because it uses move constructor not copy one. – Maestro Feb 08 '20 at 19:51
  • 1
    The book is wrong (as you yourself demonstrated). Having no move constructor is different than having a deleted move constructor. – JaMiT Feb 08 '20 at 20:13
  • 1
    Does this answer your question? [Implicit move vs copy operations and containment](https://stackoverflow.com/questions/60086366/implicit-move-vs-copy-operations-and-containment) – JaMiT Feb 08 '20 at 20:14
  • If the proposed duplicate does not address all your concerns, perhaps the other issues should be isolated from the question about the book? – JaMiT Feb 08 '20 at 20:16

0 Answers0