You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Lambda捕获列表中xx=std::move(x)会调用const拷贝构造函数?

问题分析与解答

代码示例

#include <iostream>
#include <vector>
#include <functional>

using namespace std;

struct B {
    B() {
        std::cout<<"B"<<std::endl;
    }
    
    B(B&& b2) {
        std::cout << "B&& from object moved" << b2.moved_ << std::endl;
        b2.moved_ = true;
    }
    
    B(const B&) {
        std::cout<<"const B&"<<std::endl;
    }
    
    // ~B(){
    //     std::cout<<"~B"<<std::endl;
    // }
    
    int bb=10;
    bool moved_=false;
};

struct FF {
    FF(std::function<void()> ff):ff_(std::move(ff)){}
    std::function<void()> ff_;
};

int main()
{
    std::vector<int> a{1,2,3};
    std::vector<FF> b{};
    B bb;
    std::transform(a.cbegin(), a.cend(), std::back_inserter(b), [x = std::move(bb)](auto const i) {
        
        return FF([xx = std::move(x), i]() {
            std::cout<<"FF"<<i<<std::endl;
        });
    });
    
    for(auto const& j:b) {
      j.ff_();
    }
    return 0;
}

疑问

容器b是FF类型的vector,FF以std::function<void()>对象作为构造参数。当Lambda捕获列表中执行xx = std::move(x)时,为何会调用B的const B&拷贝构造函数?预期不应存在额外的构造函数调用。

原因与解决方法

核心原因

外层Lambda未添加mutable修饰符,导致其调用运算符operator()是const限定的:

  • 默认情况下,Lambda的闭包类型是const的,它的operator()成员函数会被隐式加上const修饰。
  • 在这个const成员函数内部,闭包的成员变量x会被视为const B类型。
  • 执行xx = std::move(x)时,std::move(x)会生成const B&&类型的右值,但你的B类仅定义了接受非const右值引用的移动构造函数B(B&&),无法匹配const B&&。
  • 编译器找不到匹配的移动构造函数,只能退而调用接受const B&的拷贝构造函数来初始化xx。

解决方法

给外层Lambda添加mutable修饰符,使其operator()不再是const限定:

std::transform(a.cbegin(), a.cend(), std::back_inserter(b), [x = std::move(bb)](auto const i) mutable {
    return FF([xx = std::move(x), i]() {
        std::cout<<"FF"<<i<<std::endl;
    });
});

此时闭包成员x是可修改的B对象,std::move(x)会生成B&&类型的右值,能够匹配B的移动构造函数,不会触发拷贝构造。

内容的提问来源于stack exchange,提问作者MengMeng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 00:37:48