为什么我在 for(auto& it : myUnorderedMap) {... = std::move(it.second)} 时得到一个常量引用?

Why am I getting a const reference when I for(auto& it : myUnorderedMap) {... = std::move(it.second)}?

可重现性最低的示例 cpp.sh/2nlzz :

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

using namespace std;
int main()
{
  struct Movable {
    Movable() = default;
    Movable ( Movable && ) = default; // move constructor
    vector<int> payload;
  };
  unordered_map<int, Movable> map;
  vector<Movable> target(10);
  int i = 0; 
  for(auto& it : map) {
    target[i] = move(it.second);
    ++i;
  }
}

给我

19:15: error: use of deleted function 'main()::Movable& main()::Movable::operator=(const main()::Movable&)'
10:10: note: 'main()::Movable& main()::Movable::operator=(const main()::Movable&)' is implicitly declared as deleted because 'main()::Movable' declares a move constructor or move assignment operator

我确实为 Movable 定义了一个移动构造函数,并希望它只被移动,而不是被复制,所以它不使用常规赋值运算符也没关系,我猜它会尝试使用它,因为 it.second returns 一个 const Movable & 而不是一个 Movable &,但为什么呢?

我知道 it.first 必须是 const,因为不能乱用键,但是从值中移动应该没问题。

为什么我在这里得到一个 const 引用,我怎样才能修复代码以便我可以移动?

it.second 不是 const.

问题是用户声明移动构造函数不仅删除了隐式声明的复制构造函数和复制赋值运算符,而且还抑制了移动赋值运算符的隐式声明。

因此您的 class 没有移动赋值运算符并且复制赋值运算符被删除,导致您在尝试将 it.second 赋值给另一个 Movable 时看到的错误。

target[i] = move(it.second);

是一个赋值表达式,不是变量定义或其他会调用构造函数的对象初始化。

添加

Movable& operator=(Movable&&) = default;

到您的 class 并且可以进行移动分配。

如果您默认了移动构造函数,您可能还想自己默认移动赋值运算符。否则它会调用复制赋值运算符(已删除)。在这种情况下,编译器不会为您生成移动赋值运算符。

Movable& operator=( Movable && ) = default; // move assignment