Reason to use std::move on rvalue reference parameter
Asked Answered
G

2

16

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;
}
Grubb answered 8/11, 2019 at 5:54 Comment(2)
Seems like this is already answered here #28483750Sublimation
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.Fief
S
14

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.

Scandalize answered 8/11, 2019 at 6:1 Comment(0)
I
7

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.

Immunogenic answered 8/11, 2019 at 5:58 Comment(1)
Thank you. Two years ago, I've read cppreference for several hours to remember its effect and now I have to (re)search again, don't know if your explaination is academically correct but it is so easy to remember now :DVerada

© 2022 - 2024 — McMap. All rights reserved.