I'm trying to understand Item 17 from "Effective Modern C++" about special member function generation so I was trying some examples and am trying to reason about some behavior. In the book it says:
..that when I refer to a move operation move-constructing or move-assigning a data member or base class, there is no guarantee that a move will actually take place. “Memberwise moves” are, in reality, more like memberwise move requests, because types that aren’t move-enabled (i.e., that offer no special support for move operations, e.g., most C++98 legacy classes) will be “moved” via their copy operations. ... Furthermore, move operations won’t be generated for any class that explicitly declares a copy operation.
The code below errors out if I explicitly delete the move constructor but if I don't the object "s1" gets copy constructed without any errors. Here's a wandbox link to the same code: wandbox link. I guess I'm not understanding the difference between deleting the move constructor and not defining one.
#include <iostream>
struct S
{
S() = default;
S(const S&) {
std::cout << "Copying" << std::endl;
}
// S(S&&) = delete;
};
S return_lvalue() {
S ret{};
return ret;
}
int main() {
std::cout << "Hello world" << std::endl;
// Error here if I delete move constructor
S s1 = return_lvalue();
}
I guess I'm not understanding the difference between deleting the move constructor and not defining one.
When you do
struct S
{
S() = default;
S(const S&) {
std::cout << "Copying" << std::endl;
}
};
The compiler will not generate a move constructor. If you try to move it, overload resolution will only find S(const S&)
and you'll get a copy. With
struct S
{
S() = default;
S(const S&) {
std::cout << "Copying" << std::endl;
}
S(S&&) = delete;
};
When you move an object of type S
, overload resolution finds S(const S&)
and S(S&&)
but it picks S(S&&)
since it is the better match. Then it sees that it is deleted and you get an error.
The thing you need to remember is deleted constructors don't remove them from the class. It declares them and makes them available for overload resolution and it is only after overload resolution happens, that it checks if it is deleted.