Does std::move work with lvalue references? How does std::move work on standard containers?

我是研究僧i 提交于 2020-01-03 11:28:11

问题


#include <vector>

struct A { int a[100]; };

void foo (const A& a) {
  std::vector<A> vA; 
  vA.push_back(std::move(a));  // how does move really happen?
}

int main () {
  A a;
  foo(a);
}

The above code compiles fine. Now everywhere it's written that move avoids copying.
Following are my queries:

  1. Does the move really work when one deals with a lvalue [non]-const reference?
  2. Even with "rvalue reference", how is the copy avoided when the object is inserted into a standard container like above?

e.g.

void foo (A&& a) {  // suppose we invoke this version
  std::vector<A> vA; 
  vA.push_back(std::move(a));  // how copy is avoided?
}

回答1:


std::move doesn't do a move. It actually casts the lvalue reference to an rvalue reference. In this case, the result of the move is a const A && (which is totally useless by the way).

std::vector has an overload for a const A & and a A &&, so the overload with const A & will get chosen and the const A && is implicitly casted to const A &

The fact that std::move can be called on const objects, is strange/unexpected behavior for most programmers, though it somehow is allowed. (Most likely they had a use case of it, or none to prevent it)

More specific for your example, the move constructor of the class A will get called. As A is a POD, this most likely will just do a copy as all bits just have to move/copied to the new instance of A.

As the standard only specifies that the original object has to be in a valid though unspecified state, your compiler can keep the bits in A in place and doesn't have to reset them all to 0. Actually, most compilers will keep these bits in place, as changing them requires extra instructions, which is bad for performance.




回答2:


Created a snippet to show it. Though in your example default constructor will be called, but you get the idea.

#include <vector>
#include <iostream>

struct A { 
  int a[100];
  A() {}
  A(const A& other) {
    std::cout << "copy" << std::endl;
  }
  A(A&& other) {
    std::cout << "move" << std::endl;
  }
};

void foo(const A& a) {
  std::vector<A> vA; 
  vA.push_back(std::move(a));
}

void bar(A&& a) {
  std::vector<A> vA; 
  vA.push_back(std::move(a));
}

int main () {
  A a;
  foo(a);            // "copy"
  bar(std::move(a)); // "move"
}


来源:https://stackoverflow.com/questions/38917130/does-stdmove-work-with-lvalue-references-how-does-stdmove-work-on-standard

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!