std :: move是否适用于左值引用? std :: move如何在标准容器上运行?

时间:2016-08-12 11:42:19

标签: c++ c++11 reference language-lawyer move

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

上面的代码编译得很好。现在到处都写着move避免复制 以下是我的疑问:

  1. move在处理左值时是否真的有效 [非] - const参考?
  2. 即使使用&#34; rvalue reference&#34;,如何在对象时避免复制 插入如上所述的标准容器?
  3. 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?
    }
    

2 个答案:

答案 0 :(得分:8)

std::move没有采取行动。它实际上将左值引用转换为右值引用。在这种情况下,移动的结果是const A &&(顺便说一句,这完全没用)。

std::vector包含const A &A &&的重载,因此将选择const A &的重载并将const A &&隐式转换为{ {1}}

可以在const对象上调用const A &这一事实对于大多数程序员来说是奇怪/意外的行为,尽管它在某种程度上是被允许的。 (很可能他们有一个用例,或者没有阻止它)

对于您的示例更具体,将调用A类的移动构造函数。由于A是POD,这很可能只会复制,因为所有位都必须移动/复制到A的新实例。

由于标准只指定原始对象必须处于有效但未指定的状态,因此编译器可以将A中的位保留在原位并且不必将它们全部重置为0.实际上,大多数编译器将这些位保留在原位,因为更改它们需要额外的指令,这对性能不利。

答案 1 :(得分:0)

创建一个片段来显示它。虽然在您的示例中将调用默认构造函数,但您可以理解。

#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"
}