std::move lambda 捕获中的 const std::vector

std::move a const std::vector in a lambda capture

动机:

我正在尝试通过 lambda 捕获将 std::vector<std::unique_ptr<some_type>> 传输到另一个线程。

因为我需要在函数超出范围时不清除向量,所以我需要按值(而不是按引用)获取它。

因为它是 unique_ptrs 的矢量,我需要将它移动(而不是复制)到捕获中。

我正在使用 generalized lambda capture 在捕获时移动矢量。

说明概念的最小程序:

auto create_vector(){
    std::vector<std::unique_ptr<int>> new_vector{};
    new_vector.push_back(std::make_unique<int>(5));
    return std::move(new_vector);
}

int main() {
    const auto vec_const = create_vector();

    [vec=std::move(vec_const)](){
        std::cout << "lambda, vec size: " << vec.size() << std::endl;
    }();
}

问题:

如果我使用的是 const 本地向量,编译会因试图复制 unique_ptr 而失败。 但是,如果我删除 const 限定符,代码会编译并运行良好。

auto vec_const = create_vector();

问题:

这是什么原因? const 是否会禁用向量的 "movability" ?为什么?

在这种情况下如何确保向量的常量性?

跟进:

评论和答案提到无法从中移动 const 类型。听起来很合理,但是编译器错误并没有说清楚。在这种情况下,我希望有以下两种情况之一:

为什么那些没有发生?为什么赋值似乎只是尝试复制向量内部的 unique_ptrs(这是我对向量复制构造函数的期望)?

移动是一种破坏性操作:您在概念上更改了您移动的对象的内容。

所以是的:一个 const object 可以(也不应该)被移动。这将改变原来的 object,使其 constness 无效。

在这种情况下,vector没有vector(const vector&&),只有vector(vector &&)(移动构造函数)和vector(const vector &)(复制构造函数)。

重载解析只会将带有 const vector 参数的调用绑定到后者(以免违反 const-correctness),因此这将导致复制内容。

我同意:错误报告很糟糕。当您遇到 unique_ptr 的问题时,很难设计有关 vector 的错误报告。这就是为什么 required from ...., required from ... 的整个尾巴抹杀了视图。

根据你的问题和你的代码,我可以看出你没有完全掌握移动语义:

  • 你不应该 move 变成 return 值; return 值已经是右值,所以没有意义。
  • std::move并没有真正移动任何东西,它只是将你想要的变量的限定符更改为'move from',以便选择正确的接收者(使用'binding'规则) .真正改变原object.
  • 内容的是接收函数

当您将某物从 A 移动到 B 时,移动行为必然意味着 A 被修改,因为移动后 A 可能不会不再有原来 A 中的任何内容。这就是移动语义的全部目的:提供最佳实现,因为允许修改移出的对象:其内容以某种快速而神秘的方式转移到 B,将 A 留在一些有效但未指定的状态。

因此,根据定义,A 不能是 const