12

I was reading a book about data structure implemented in C++, I dont understand a code snippet, it's part of vector class

void push_back(object &&x) {
        //do something
        objects[size++] = std::move(x);
    }

I know that std::move return a rvalue reference of the object, but the push_back member function already has rvalue reference x as parameter, isn't the std::move here unnecessary?

Another question is if we have a rvalue reference of a class object, we still need to use std::move on its member if we want to call move instead of copy right? like the code below:

A& operator=(A&& other) {
     member = std::move(other.member);
     return *this;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
codesavesworld
  • 587
  • 3
  • 10
  • Seems like this is already answered here https://stackoverflow.com/questions/28483250/rvalue-reference-is-treated-as-an-lvalue – StoryTeller - Unslander Monica Nov 08 '19 at 06:05
  • 1
    OT: What book was that? `objects[size++] = std::move(x);` requires a valid object of vector's value type at `&objects[size]`, which is not how `push_back` should work. Vectors typically use placement new (allocator's `construct` generally) to create a new object there, not an assignment operator. Also note that if the assignment throws (by throwing move assignment op. or copy assignment op.), then, the `size` will be incremented and the state of the vector will be incorrect. Better to do `size++;` at the next line. – Daniel Langr Nov 08 '19 at 06:30

2 Answers2

9

isn't the std::move here unnecessary?

No. Types and value categories are different things.

(emphasis mine)

Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.

The following expressions are lvalue expressions:

the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;

std::move converts lvalue to rvalue (xvalue). As a named variable, x is an lvalue, std::move converts it to rvalue in objects[size++] = std::move(x); then the move assignment operator is supposed to be used. Otherwise, copy assignment operator will be used instead; lvalue can't be bound to rvalue reference.

we still need to use std::move on its member if we want to call move instead of copy right?

Yes, same reason as above.

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

x has a name, thus it's an lvalue inside the function. The rvalue reference was bound to the lvalue x. std::move casts it back to the rvalue that was passed in.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70