0

If I use std::move on a stack object in the current scope, the contents are moved to destination leaving the source empty.

#include <iostream> #include <string> #include <utility> #include <vector> int main() { std::string str("stackoverflow"); std::vector<std::string> vec; vec.emplace_back(std::move(str)); std::cout << "vec[0]: " << vec[0] << std::endl; std::cout << "str: " << str << std::endl; } 

Result:

vec[0]: stackoverflow str: 

If I use the std::move for a rvalue or const lvalue function arguments, the contents are copied.

#include <iostream> #include <memory> #include <vector> #include <utility> void process_copy(std::vector<int> const & vec_) { std::vector<int> vec(vec_); vec.push_back(22); std::cout << "In process_copy (const &): " << std::endl; for(int & i : vec) std::cout << i << ' '; std::cout << std::endl; } void process_copy(std::vector<int> && vec_) { std::vector<int> vec(vec_); vec.push_back(99); std::cout << "In process_copy (&&): " << std::endl; for(int & i : vec) std::cout << i << ' '; std::cout << std::endl; } int main() { std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; process_copy(std::move(v)); std::cout << "In main: " << std::endl; for(int & i : v) std::cout << i << ' '; std::cout << std::endl; std::cout << "size: " << v.size() << std::endl; } 

Result:

In process_copy (&&): 0 1 2 3 4 5 6 7 8 9 99 In main: 0 1 2 3 4 5 6 7 8 9 size: 10 

Why is the behavior of std::move different?

3
  • 1
    Remember that std::move doesn't actually move anything. It is just a cast to rvalue reference. Whether that rvalue reference is subsequently moved or copied depends on context and whether or not the object implements move operations and whether or not the source object is const. Commented Feb 10, 2020 at 9:19
  • Related: stackoverflow.com/questions/7510182/… Commented Feb 10, 2020 at 9:19
  • In the first example, the one actually moving the ownership of the data is the move constructor of the std::string. In the second example, you're just sending an rvalue ref. You can manually take the ownership of the passed std::vector here. Commented Feb 10, 2020 at 9:25

2 Answers 2

3

You need to use std::move if the value is bound to a variable even it is declared as rvalue revefernce (&&). i.e. it should be:

void process_copy(std::vector<int> && vec_) { std::vector<int> vec(std::move(vec_)); ... } 
Sign up to request clarification or add additional context in comments.

4 Comments

To add to this, one should note that the one actually transferring the ownership of the data is the move constructor.
Is it not std::forward which should be used to give a better readability in that case?
@Klaus vec_ is not a forwarding reference so I'd say move is better suited.
@Klaus It is true that std::forward will work as well but we should understand the purpose of std::forward i.e. "perfect-forwarding". Here vec_ is an rvalue ref, so it's better to just straightaway use std::move, which is meant for this.
1

Your vector is actually copied, not moved. The reason for this is, although declared as an rvalue reference, vec_ denotes an lvalue expression inside the function body. Thus the copy constructor of std::vector is invoked, and not the move constructor. The reason for this is, that vec_ is now a named value, and rvalues cannot have names, so it collapses to an lvalue. The following code will fail to compile because of this reason:

void foo(int&& i) { int&& x = i; } 

In order to fix this issue, you have to make vec_ nameless again, by calling std::move(vec_).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.