结构化绑定与移动语义:能否将vector移入Lambda?
问题:Lambda捕获中vector的移动还是拷贝?
给定如下代码片段:
std::unordered_map<int, std::vector<int>> myMap; // ... 初始化'myMap'并填入一些值 for (auto&& [Id, deviceIds] : myMap) { auto l = [deviceIds = std::forward<decltype(deviceIds)>(deviceIds)]() { // 在此处使用deviceIds进行操作 }; }
由于vector的体积可能很大,我尝试将deviceIds移入lambda中。请问上述代码会执行移动操作还是会因某些原因执行拷贝操作?
回答
这段代码会执行拷贝操作,具体原因如下:
- 首先看range-based for循环里的
auto&& [Id, deviceIds]:因为myMap是一个非const的左值容器,结构化绑定后的deviceIds实际是std::vector<int>&类型(左值引用)。 - 当你调用
std::forward<decltype(deviceIds)>(deviceIds)时,decltype(deviceIds)是左值引用类型,所以std::forward会把它转发成左值。而vector的移动构造函数只接受右值参数,这里传入左值的话,最终会触发拷贝构造函数,lambda捕获的是原vector的副本。
如果想要实现移动捕获,有两种可行方式:
- 用
std::move强制将左值转为右值:
auto l = [deviceIds = std::move(deviceIds)]() { // 在此处使用deviceIds进行操作 };
这样deviceIds会被移动到lambda的捕获变量中,原map里的这个vector会变成空(处于可析构、可赋值的有效状态)。
- 如果不想破坏原map中的vector,那就只能执行拷贝操作——毕竟移动操作会转移资源所有权,原对象的资源会被掏空。
内容的提问来源于stack exchange,提问作者David Hovsepyan
相关产品推荐
相关产品推荐

