> 技术文档 > 【C++】Lambda表达式_c++ lamda表达式

【C++】Lambda表达式_c++ lamda表达式


目录

    • 一、Lambda表达式基础
      • 1.1 核心概念
      • 1.2 基础语法
    • 二、捕获列表详解
      • 2.1 捕获方式对比
      • 2.2 捕获示例
    • 三、参数与返回类型
      • 3.1 参数传递
      • 3.2 返回类型推导
    • 四、高级特性与应用
      • 4.1 立即执行Lambda
      • 4.2 泛型Lambda(C++14)
      • 4.3 捕获表达式(C++14)
      • 4.4 递归Lambda
    • 五、典型应用场景
      • 5.1 STL算法
      • 5.2 多线程编程
      • 5.3 延迟执行
    • 六、注意事项
      • 6.1 悬挂引用
      • 6.2 捕获this指针
    • 七、性能优化建议
    • 八、C++标准演进
    • 九、最佳实践总结
    • 如果这篇文章对你有所帮助,渴望获得你的一个点赞!

一、Lambda表达式基础

1.1 核心概念

Lambda表达式是C++11引入的匿名函数对象,具有以下特点:

  • 就地定义,无需单独命名
  • 可捕获上下文变量
  • 自动推导返回类型(多数情况)
  • 可作为函数参数传递

1.2 基础语法

[capture](parameters) mutable -> return_type { // 函数体 }

含义

  1. [capture]:捕获列表,用于指定Lambda如何访问外部变量。

  2. (parameters):参数列表,和普通函数的参数类似,但需要注意Lambda参数C++14起才支持auto类型。且不允许有默认参数。

  3. mutable:这个关键字的作用是允许修改按值捕获的变量,或者调用非const的成员函数。默认情况下Lambda的operator()是const的,所以不加mutable的话,无法修改按值捕获的变量。

  4. return_type:返回类型,通常可以自动推导,但在某些情况下需要显式指定,比如函数体内有多个return语句且返回类型不一致时。

  5. 函数体:Lambda的具体实现代码,和普通函数类似,但可以访问捕获的变量。

最小示例

auto greet = [] { std::cout << \"Hello Lambda!\"; };greet(); // 输出:Hello Lambda!

二、捕获列表详解

2.1 捕获方式对比

捕获方式 语法 生命周期 修改权限 示例 值捕获 [x] 创建时拷贝 需要mutable int x=5; [x]{...}; 引用捕获 [&x] 依赖原变量 直接修改原值 [&x]{x=10;}; 隐式值捕获 [=] 创建时全拷贝 需要mutable [=]{return a+b;}; 隐式引用捕获 [&] 依赖原变量 直接修改原值 [&]{modify(a);}; 捕获当前类的this指针 [this] 依赖外部对象 不需要mutable [this]{return m_var;} 混合捕获 [=, &x] 组合使用 按各自规则 [=,&err]{...};

2.2 捕获示例

int main() { int a = 10, b = 20; // 值捕获示例 auto value_capture = [a] { return a * 2;  // 捕获时的值:a = 10 }; a = 100; // a修改,不影响之前值捕获的值,因为创建时拷贝了 std::cout << value_capture(); // 输出:20 // 引用捕获示例 auto ref_capture = [&b] { b += 5;  // 直接修改原变量 }; ref_capture(); std::cout << b; // 输出:25}

三、参数与返回类型

3.1 参数传递

// 显式参数类型auto add_int = [](int a, int b) { return a + b; };// C++14起支持auto参数auto generic_add = [](auto x, auto y) { return x + y; };std::cout << add_int(3, 5); // 输出:8std::cout << generic_add(2.5, 3.7); // 输出:6.2

3.2 返回类型推导

当函数体包含多个return语句且类型不同时,需要显式指定返回类型:

auto safe_divide = [](int x, int y) -> double { if(y == 0) { return 0.0; } else { return x / static_cast<double>(y); }};

四、高级特性与应用

4.1 立即执行Lambda

const auto result = [](int base) { int sum = 0; for(int i = 1; i <= base; ++i) { sum += i; } return sum;}(100);  // 立即计算1-100的和std::cout << result; // 输出:5050

4.2 泛型Lambda(C++14)

auto make_adder = [](auto increment) { return [increment](auto x) { return x + increment; };};auto add5 = make_adder(5);std::cout << add5(3.14); // 输出:8.14std::cout << add5(\"abc\"); // 编译错误(字符串不能+5)

4.3 捕获表达式(C++14)

int x = 10;auto lambda = [y = x * 2] { // 初始化捕获 return y + 5; };std::cout << lambda(); // 输出:25

4.4 递归Lambda

auto factorial = [](auto self, int n) -> int { return n <= 1 ? 1 : n * self(self, n-1);};std::cout << factorial(factorial, 5); // 输出:120

五、典型应用场景

5.1 STL算法

std::vector<int> numbers{3, 1, 4, 1, 5, 9, 2, 6};std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; });  // 降序排列int count = std::count_if(numbers.begin(), numbers.end(), [threshold=5](int x) { return x > threshold; }); // 统计大于5的元素

5.2 多线程编程

#include #include void parallel_process() { std::vector<std::thread> workers; for(int i=0; i<5; ++i) { workers.emplace_back([i] { // 每个线程捕获不同的i值 std::cout << \"Thread \" << i << \" working\\n\"; }); } for(auto& t : workers) { t.join(); }}

5.3 延迟执行

auto create_logger = [](const std::string& prefix) { return [=](const auto& message) { // 值捕获prefix std::cout << \"[\" << prefix << \"] \" << message << \"\\n\"; };};auto error_log = create_logger(\"ERROR\");error_log(\"File not found\"); // [ERROR] File not found

六、注意事项

6.1 悬挂引用

auto create_dangerous_lambda() { int local = 42; return [&local] { return local; }; // 危险!}  // local离开作用域被销毁auto bad_lambda = create_dangerous_lambda();std::cout << bad_lambda();  // 未定义行为!

解决方案:使用值捕获或shared_ptr

auto create_safe_lambda() { auto ptr = std::make_shared<int>(42); return [ptr] { return *ptr; }; // 共享所有权}

6.2 捕获this指针

class Widget { int value = 100;public: auto get_handler() { return [this] {  // 捕获当前对象指针 return value * 2; }; }};

七、性能优化建议

  1. 小Lambda优先传值:避免不必要的引用捕获开销
  2. 避免在循环中创建大型Lambda:可能影响缓存局部性
  3. 慎用[=]和[&]:明确捕获需要的变量
  4. 考虑const correctness:默认operator()const

八、C++标准演进

版本 新特性 示例 C++11 基础Lambda语法 [](int x) { return x; } C++14 泛型参数,初始化捕获 [x=5](){...} C++17 constexpr Lambda constexpr auto l = []{}; C++20 模板参数列表,概念约束 [](T x){...}

九、最佳实践总结

  1. 保持简洁:Lambda最适合短小逻辑
  2. 明确捕获:避免隐式捕获所有变量
  3. 注意生命周期:引用捕获需确保有效性
  4. 合理使用auto:简化泛型Lambda声明
  5. 性能敏感区谨慎使用:理解编译器生成的开销
// 综合示例:工厂模式auto create_multiplier(int factor) { return [factor](int x) mutable { // 值捕获factor factor += x % 2;  // 修改拷贝的值 return x * factor; };}auto doubler = create_multiplier(2);std::cout << doubler(5); // 5*(2+1)=15std::cout << doubler(3); // 3*(2+1)=9

如果这篇文章对你有所帮助,渴望获得你的一个点赞!

在这里插入图片描述