std::move 可以与左值引用一起使用吗? std::move 如何在标准容器上工作?

问题描述 投票:0回答:3
#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. 即使使用“右值引用”,当对象 被插入到像上面这样的标准容器中吗?

例如

void foo (A&& a) {  // suppose we invoke this version
  std::vector<A> vA; 
  vA.push_back(std::move(a));  // how copy is avoided?
}
c++ c++11 reference language-lawyer move
3个回答
19
投票

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

std::vector
具有
const A &
A &&
的重载,因此将选择
const A &
的重载,并且
const A &&
隐式转换为
const A &

可以在 const 对象上调用

std::move
的事实对于大多数程序员来说是奇怪/意外的行为,尽管它在某种程度上是允许的。 (很可能他们有它的用例,或者没有阻止它)

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

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


3
投票

创建了一个片段来展示它。虽然在您的示例中将调用默认构造函数,但您明白了。

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

0
投票

将调用 void func(Test&&):

#include <iostream>
#include <string>
using namespace std;

class Test{
    int x = 1;
};

void func(const Test&){
    cout << "from contst Test&" << endl;
}

void func(Test&&){
    cout << "from Test&&" << endl;
}

void func2(Test &t){
    func(std::move(t));
}

int main(){
    cout << "hello" << endl;

    Test t;
    func2(t);
}
© www.soinside.com 2019 - 2024. All rights reserved.