Why does calling std::move on a const
object call the copy constructor when passed to another object? Specifically, the code
#include <iostream> struct Foo { Foo() = default; Foo(Foo && x) { std::cout << "Move" << std::endl; } Foo(Foo const & x) = delete; }; int main() { Foo const x; Foo y(std::move(x)); }
fails to compile with the message:
g++ -std=c++14 test07.cpp -o test07 test07.cpp: In function 'int main()': test07.cpp:10:36: error: use of deleted function 'Foo::Foo(const Foo&)' Foo const x; Foo y(std::move(x)); ^ test07.cpp:6:5: note: declared here Foo(Foo const & x) = delete; ^ Makefile:2: recipe for target 'all' failed make: *** [all] Error 1
Certainly, I expect it to fail because we can't move a const
value. At the same time, I don't understand the route that the code takes before it tries to call the copy constructor. Meaning, I know that std::move
converts the element to an x-value, but I don't know how things proceed after that with respect to const
.
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
If an object is passed as value to the Copy Constructor then its copy constructor would call itself, to copy the actual parameter to the formal parameter. Thus an endless chain of call to the copy constructor will be initiated.
Because passing by value to a function means the function has its own copy of the object. To this end, the copy constructor is called.
The type of the result of calling std::move
with a T const
argument is T const&&
, which cannot bind to a T&&
parameter. The next best match is your copy constructor, which is deleted, hence the error.
Explicitly delete
ing a function doesn't mean it is not available for overload resolution, but that if it is indeed the most viable candidate selected by overload resolution, then it's a compiler error.
The result makes sense because a move construction is an operation that steals resources from the source object, thus mutating it, so you shouldn't be able to do that to a const
object simply by calling std::move
.
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