'why non-movable Object still a copy
Consider the following code, Entity object is non-movable. I know that std::move(Obj) just cast the Obj to a rvalue reference Obj. And I also know that rvalue reference variable is still a lvalue object. But I still confusing why statement auto temp = std::move(a) can call copy constructor, statement a = std::move(b); can call copy assignment operator. Since, std::move(a) is a rvalue reference, why it can still call lvalue constructor.
#include <iostream>
template<typename T>
void my_swap(T& a, T& b) {
auto temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}
class Entity{
int _id;
public:
Entity(int id) :_id(id) {std::cout << "construtor\n" << std::endl;}
Entity(const Entity& other) {
_id = other._id;
std::cout << "copy constructor\n" << std::endl;
}
Entity& operator= (const Entity& other) {
if (&other == this) return *this;
this->_id = other._id;
std::cout << "copy assignment operator\n";
return *this;
}
};
int main() {
Entity e1 = Entity(10);
Entity e2 = Entity(20);
my_swap(e1,e2);
return 0;
}
Solution 1:[1]
Entity object is non-movable
No. Even it doesn't have move constructor/assignment-operator, it has copy constructor/assignment-operator taking lvalue-reference to const. std::move(a) and std::move(b) are rvalue (xvalue) expressions and they could be bound to lvalue-reference to const.
You might also check std::is_move_constructible:
Types without a move constructor, but with a copy constructor that accepts const T& arguments, satisfy std::is_move_constructible.
Solution 2:[2]
If you want to make your Entity non-movable, then add the move-constructor and move-assignment operator as deleted:
Entity(Entity&& other) = delete;
Entity& operator= (Entity&& other) = delete;
Solution 3:[3]
Considering the following code, Entity object is non-movable.
No, it isn't. Entity is movable.
But I still confusing why statement auto temp = std::move(a)
Lvalue reference to const can be bound to an rvalue. The copy constructor accepts an lvalue reference to const parameter. That parameter can be bound to the std::move(a) rvalue argument.
And I also know that rvalue reference variable is still a lvalue object.
Not quite. References are not objects. An id-expression that names anything, including an rvalue reference varaible, is an lvalue.
Entity is movable. Does is because there exists default move constructor/assignment-operator.
It is movable because it has a copy constructor/assignment operator, and it doesn't have deleted move constructor/assignment operator.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Frodyne |
| Solution 3 |
