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.