Quoted from C++ Primer
if we explicitly ask the compiler to generate a move operation by using
= default
, and the compiler is unable to move all the members, then the move operation will be defined as deletedthe move constructor is defined as deleted if the class has a member that defines its own copy constructor but does not also define a move constructor, or if the class has a member that doesn’t define its own copy operations and for which the compiler is unable to synthesize a move constructor
Some code seems to violate this rule:
#include <utility>
#include <iostream>
struct X {
X() = default;
X(const X&) { std::cout << "X(const X&)" << std::endl; }
int i;
};
struct hasX {
hasX() = default;
hasX(const hasX &) = delete;
hasX(hasX &&) = default;
X mem;
};
int main()
{
hasX hx, hx2 = std::move(hx); //output is X(const X&)
}
X
doesn't define move constructor and compiler can't synthesize one for it.
According to the rule above, hasX
's move constructor is deleted.
However, because hasX
's copy constructor is deleted, hx2 = std::move(hx)
must call move constructor to output "X(const X&)"
, which shows hasX
's move constructor is defined and it use X
's copy constructor to "move". This seems to violate the rule above.
So, is't defined in C++ standard or just a compiler implementation?
Compiler I tested: VS2015 and a online compiler
Thank you for help!
Your book seems to be wrong. Copying is a valid move operation so as long as the member has a copy constructor in the form of const type&
, so it can bind to rvalues, the move operation will fall back to a copy.
In your example
hasX(hasX &&) = default;
Can be replaced with
hasX(hasX &&rhs) : mem(std::move(rhs.mem)) {}
as that is what the default does and it will compile just fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With