类型一:值捕获(Copy Capture)
核心要点:定义时(而非调用时)将外部变量的值拷贝一份存入闭包。默认情况下,闭包内的副本是只读的(不可修改外部原件),且不影响外部变量。

#include <iostream>
int main() {
    int c = 10;
    // 值捕获 c(闭包内部存有 c 的独立副本)
    auto add = [c](int a) -> int { 
        // c = 20; // 错误!默认 operator() 是 const,不可修改副本
        return a + c; 
    };
    c = 999; // 外部修改不影响闭包内的副本
    std::cout << add(5) << std::endl; // 输出 15(5 + 10)
    return 0;
}

类型二:引用捕获(Reference Capture)
核心要点:闭包内部存储的是外部变量的引用(地址)。在 Lambda 体内操作该变量会直接影响外部原件。注意:必须确保 Lambda 调用时外部变量仍然存活,否则产生悬垂引用。

#include <iostream>
int main() {
    int c = 10;
    // 引用捕获 c(闭包内存放 c 的地址)
    auto add = [&c](int a) -> int { 
        c = 20; // 直接修改外部变量
        return a + c; 
    };
    std::cout << add(5) << std::endl; // 输出 25(5 + 20)
    std::cout << "外部 c = " << c << std::endl; // 输出 20(已被修改)
    return 0;
}

类型三:空列表捕获(无捕获 / No Capture)
核心要点:Lambda 只能使用参数列表、全局变量、静态变量。无法访问任何外部作用域的局部变量(非静态)。因为不捕获任何东西,它最轻量,且能隐式转换为函数指针。

#include <iostream>
int global = 100;

int main() {
    int local = 10;
    // 无法访问 local,因为没捕获
    // auto f = []() { return local; }; // ❌ 编译错误

    // 只能用参数或全局变量
    auto add = [](int a, int b) -> int { 
        return a + b + global; // 全局变量可直接访问
    };
    std::cout << add(1, 2) << std::endl; // 输出 103(1+2+100)
    return 0;
}

注意:

1:隐式捕获:手动书写捕获列表有时候是非常复杂的,这种机械性的工作可以交给编译器来处理,这时候可以在捕 获列表中写一个&(引用捕获) 或 =(值捕获) 向编译器声明采用引用捕获或者值捕获。

2:Lambda 表达式执行时,分为捕获和传参两个过程。捕获在被创建(定义)的时候就完成了,传参在执行到调用处(即 Add(1, 2) 这一行)的时候才发生。lambda表达式执行时,分为捕获和传参两个过程。捕获在被创建的时候就完成了,传参在执行到这的时候。与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在 lambda表达式被 创建时拷贝,而非调用时才拷贝

3:

lambda表达式可以通过捕获列表捕获一定范围内的变量:

[ ]不捕获任何变量。

[&]捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。

[=]捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。

[=, &foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。

[bar,&foo]按值捕获bar变量,同时不捕获其他变量。

[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使 用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变

更多推荐