为什么在移动 `unique_ptr` 时在 lambda 中调用复制构造函数?

Why is the copy constructor invoked in a lambda while moving a `unique_ptr`?

为什么这段代码编译失败?

#include <memory>
#include <utility>

int foo() {
    auto num = std::make_unique<int>(1);
    auto func = [s = std::move(num)] {
        auto u = std::move(s); <-- ERROR!
        return *u;
    };
    return func();
}

错误是:

<source>:8:14: error: call to deleted constructor of 'std::unique_ptr<int, std::default_delete<int>>'
        auto u = std::move(s);
             ^   ~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/unique_ptr.h:468:7: note: 'unique_ptr' has been explicitly marked deleted here
      unique_ptr(const unique_ptr&) = delete;

我不明白为什么要调用复制构造函数,这显然是 unique_ptr 故意删除的。我能理解什么错误是什么,但不知道为什么它首先在那里。

这是我认为会发生的情况,但我不确定。如果我将这个 lambda 解压成一种 structoperator() as

template <typename T>
struct Lambda{
  :
  :
  operator() const{
    auto u = std::move(s); // <-- error
  }
  private:
  std::unique_ptr<T> s;
};

我认为这将无法编译,因为 move(s) 会更改 s 的值,这在 const 函数中是不允许的。所以编译应该以 lamda 的不变性为由失败。甚至通过将 lambda 更改为 mutable 来修复此错误。但另一个似乎是使 s 成为 shared_ptr(根据我的说法应该失败,因为 lambda 仍然是不可变的),这就是我感到困惑的地方。

我在 clanggcc 上都试过了,结果相似。那么,有人可以帮助我消除理解上的差距吗?

这是因为您试图在 const 成员函数中移动数据成员。

std::move(s)的类型和类别是const unique_ptr&&。没有重载 unique_ptr(const unique_ptr&&),唯一可行的是 unique_ptr(const unique_ptr&).

I think this would fail to compile because the move(s) would change the value of s which isn't allowed in a const function.

不,move 只是一个 static_cast