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 类型。听起来很合理,但是编译器错误并没有说清楚。在这种情况下,我希望有以下两种情况之一:
std::move(vec_const)
应该抛出一个关于从 const 移动(将其转换为右值)不可能的错误。
- 矢量移动构造函数告诉我它拒绝接受常量右值。
为什么那些没有发生?为什么赋值似乎只是尝试复制向量内部的 unique_ptrs(这是我对向量复制构造函数的期望)?
移动是一种破坏性操作:您在概念上更改了您移动的对象的内容。
所以是的:一个 const object 可以(也不应该)被移动。这将改变原来的 object,使其 const
ness 无效。
在这种情况下,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
。
动机:
我正在尝试通过 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 类型。听起来很合理,但是编译器错误并没有说清楚。在这种情况下,我希望有以下两种情况之一:
std::move(vec_const)
应该抛出一个关于从 const 移动(将其转换为右值)不可能的错误。- 矢量移动构造函数告诉我它拒绝接受常量右值。
为什么那些没有发生?为什么赋值似乎只是尝试复制向量内部的 unique_ptrs(这是我对向量复制构造函数的期望)?
移动是一种破坏性操作:您在概念上更改了您移动的对象的内容。
所以是的:一个 const object 可以(也不应该)被移动。这将改变原来的 object,使其 const
ness 无效。
在这种情况下,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
。