简体   繁体   English

std ::在lambda捕获中移动const std :: vector

[英]std::move a const std::vector in a lambda capture

Motivation: 动机:

I'm trying to transfer a std::vector<std::unique_ptr<some_type>> to a different thread, via a lambda capture. 我正在尝试通过lambda捕获将std::vector<std::unique_ptr<some_type>>传输到其他线程。

Since I need the vector to not be cleaned up when the function goes out of scope, I need to take it by value (and not by reference). 由于我需要在函数超出范围时不清理向量,因此需要按值(而不是按引用)使用向量。

Since it's a vector of unique_ptrs, I need to move (and not copy) it into the capture. 由于它是unique_ptrs的向量,因此我需要将其移动(而不是复制)到捕获中。

I'm using a generalized lambda capture to move the vector while capturing. 我正在使用广义lambda捕获来在捕获时移动向量。

Minimal program to illustrate the concept: 最少的程序来说明这个概念:

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

Issue: 问题:

If I'm using a const local vector, compilation fails due to attempting to copy the unique_ptr s. 如果我使用的是const局部向量,则由于尝试复制unique_ptr而导致编译失败。 However if I remove the const qualifier, the code compiles and runs well. 但是,如果删除const限定符,代码将编译并运行良好。

auto vec_const = create_vector();

Questions: 问题:

What's the reason for this? 这是什么原因? Does being const disable the "movability" of the vector? const是否会禁用向量的“可移动性”? Why? 为什么?

How would I ensure the constness of a vector in such a scenario? 在这种情况下,我将如何确保向量的恒定性?

Follow-up: 跟进:

The comments and answers mention that a const type can't be moved from. 注释和答案提到const类型不能从中移出。 Sounds reasonable, however the the compiler errors fail to make it clear. 听起来很合理,但是编译器错误未能明确说明。 In this case I would expect one of two things: 在这种情况下,我期望以下两件事之一:

  • The std::move(vec_const) should throw an error regarding moving from const (casting it to rvalue) being impossible. std::move(vec_const)应该引发错误,这是关于不可能从const(将其广播到rvalue)转移的。
  • The vector move-constructor telling me that it refuses to accept const rvalues. 向量move-constructor告诉我它拒绝接受const rvalue。

Why don't those happen? 为什么这些不发生? Why does instead the assignment seems to just try to copy the unique_ptrs inside the vector (which is what I'd expect from the vectors copy-constructor)? 为什么相反,该分配似乎只是尝试在向量内部复制unique_ptrs(这是我希望从向量copy-constructor获得的结果)?

Moving is a disruptive operation: you conceptually change the content of the thing you move from. 移动是一种破坏性的操作:您从概念上更改了移动对象的内容。

So yes: a const object can (and should) not be moved from. 所以是的:const对象不能(也不应该)移出。 That would change the original object, which makes its const ness void. 那将改变原始对象,从而使其const无效。

In this case, vector has no vector(const vector&&) , only vector(vector &&) (move constructor) and vector(const vector &) (copy constructor). 在这种情况下, vector没有vector(const vector&&) ,只有vector(vector &&) (移动构造函数)和vector(const vector &) (复制构造函数)。

Overload resolution will only bind a call with const vector argument to the latter (lest const-correctness would be violated), so this will result in copying the contents. 重载解析只会将带有const vector参数的调用绑定到后者(不会违反const正确性),因此这将导致复制内容。

I agree: error reporting sucks. 我同意:错误报告很糟糕。 It's hard to engineer an error report about vector when you hit a problem with unique_ptr . 当您遇到unique_ptr问题时,很难设计出关于vector的错误报告。 That's why the whole tail of required from ...., required from ... obliterates the view. 这就是为什么...的全部尾部, required from ...., required from ...的全部尾部消除了视图的原因。

From your question, and your code, I can tell that you don't fully grasp the move semantics stuff: 从您的问题和您的代码中,我可以看出您没有完全掌握移动语义方面的知识:

  • you shouldn't move into a return value; 你不应该move到一个返回值; a return value is already an rvalue, so there's no point. 返回值已经是一个右值,所以没有意义。
  • std::move does not really move anything, it only changes the qualifier of the variable you want to 'move from', so that the right receiver can be selected (using 'binding' rules). std::move并不会真正移动任何东西,它只会更改您要从其“移出”的变量的限定符,以便可以选择正确的接收者(使用“绑定”规则)。 It is the receiving function that actually changes the contents of the original object. 接收功能实际上改变了原始对象的内容。

When you are moving something from A to B , then act of moving must necessarily mean that A gets modified, since after the move A may no longer have whatever was in A , originally. 当您将某物从A移动到B ,移动的动作必然意味着A被修改了,因为在移动之后, A可能不再拥有A任何东西。 This is the whole purpose of move semantics: to provide an optimal implementation since the moved-from object is allowed to be modified: its contents getting transferred in some fast and mysterious way into B , leaving A in some valid, but unspecified, state. 这是移动语义的全部目的:提供一个最佳实现,因为允许修改从移动的对象:其内容以某种快速而神秘的方式转移到B ,而使A处于某种有效但未指定的状态。

Consequently, by definition, A cannot be const . 因此,根据定义, A不能为const

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM