我正在尝试通过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是否会禁用向量的“可移动性”?为什么?
在这种情况下如何确保向量的恒定性?
注释和答案提到不能从中移除const类型。听起来很合理,但是编译器错误未能明确说明。在这种情况下,我期望以下两件事之一:
std::move(vec_const)
应该抛出一个错误,关于不可能从const(将其投射到右值)转移。为什么这些不发生?为什么相反,分配似乎只是尝试在向量中复制unique_ptrs(这是我希望从向量copy-constructor获得的结果)?
答案 0 :(得分:3)
移动是一种破坏性的操作:您从概念上更改了要移动的事物的内容。
所以是的:const对象不能(并且应该)从中移出。那会改变原始对象,从而使其const
的性质无效。
在这种情况下,vector
没有vector(const vector&&)
,只有vector(vector &&)
(移动构造函数)和vector(const vector &)
(副本构造函数)。
重载解析将仅将带有const vector
参数的调用绑定到后者(不会违反const正确性),因此将导致复制内容。
我同意:错误报告很糟糕。当您遇到vector
的问题时,很难设计关于unique_ptr
的错误报告。这就是required from ...., required from ...
的整个尾部使视图消失的原因。
从您的问题和代码中,我可以看出您没有完全掌握移动语义学的东西:
move
返回一个返回值;返回值已经是一个右值,所以没有意义。std::move
并不会真正移动任何东西,它只会更改要“移出”的变量的限定符,以便可以选择正确的接收者(使用“绑定”规则)。接收功能实际上是更改原始对象的内容。答案 1 :(得分:3)
当您将某物从A
移到B
时,那么移动的行为必定意味着A
被修改了,因为移动A
之后可能不再具有最初是A
中的任何内容。这是移动语义的全部目的:提供一个最佳实现,因为可以修改move-from对象:将其内容以某种快速而神秘的方式转移到B
中,而将A
保留在其中一些有效但未指定的状态。
因此,根据定义,A
不能为const
。