1

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;
}

amont
  • 81
  • 8
  • 1
    temporary/rvalue reference can bind to const reference. – Jarod42 May 03 '22 at 13:20
  • Thanks, you're right. I know that the swap function in c++ library is implemented like `my_swap`. But how it make the assignment works for a non-movable object. – amont May 03 '22 at 13:25
  • Why do you think it isn't movable? – molbdnilo May 03 '22 at 13:27
  • The semantics of a move is that the source object has the value the moved from object "had". It doesn't require the moved from object to be empty or to have any specific state. If you preform a copy to do that, then you have technically satisfied the requirements. – NathanOliver May 03 '22 at 13:28
  • @molbdnilo Suppose the class doesn't have a move constructor / assignment operator. Or make them delete. – amont May 03 '22 at 13:32
  • 1
    @amont: Not having them and deleting them are two different things. – Nicol Bolas May 03 '22 at 15:36

3 Answers3

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
0

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.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

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;
Frodyne
  • 3,547
  • 6
  • 16