【C++】Lambda表达式

devtools/2025/2/5 10:46:33/

目录

    • 一、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]创建时拷贝需要mutableint 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);         // 输出:8
std::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.14
std::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 <thread>
#include <vector>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) {   // 值捕获prefixstd::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++17constexpr Lambdaconstexpr auto l = []{};
C++20模板参数列表,概念约束[]<typename T>(T x){...}

九、最佳实践总结

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

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

在这里插入图片描述


http://www.ppmy.cn/devtools/156252.html

相关文章

从理论到实践:Linux 进程替换与 exec 系列函数

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 在Linux中&#xff0c;进程替换&#xff08;Process Substitution&#xff09;是一个非常强大的特性&#xff0c;它允许将一个进程的输出直接当作一个文件来处理。这种技术通常用于Shell脚本和命令行操作中…

Vue.js 新的生命周期钩子:`onMounted`, `onUpdated` 等

Vue.js 新的生命周期钩子&#xff1a;onMounted, onUpdated 等 今天我们来聊聊 Vue 3 中的生命周期钩子&#xff0c;特别是 onMounted、onUpdated 等。如果你对如何在 Vue 3 的组合式 API&#xff08;Composition API&#xff09;中使用这些钩子感到困惑&#xff0c;那么这篇文…

vim操作简要记录

操作容易忘记&#xff0c;记录一下基本使用的 :wq保存退出 :w :q :q! :wq! i I a A 方向键 h左 j下 k上 l右 dd删除方行&#xff08;这其实是剪切行操作&#xff0c;不过一般用作删除&#xff0c;长按可删除&#xff0c;不过按.执行上一次操作删除更快&#xff09; .执行上…

什么是REStful API,其设计核心原则(core principle)是什么

RESTful API(Representational State Transfer API)是一种基于Web的架构风格,它通过HTTP协议提供客户端与服务器之间的交互。RESTful API基于资源的概念,资源通常通过URL表示,客户端与服务器之间通过请求和响应交换数据。它常用于构建轻量级的、可扩展的网络服务。 RESTf…

力扣 45. 跳跃游戏 II

&#x1f517; https://leetcode.cn/problems/jump-game-ii 题目 给一个数组 nums&#xff0c;最开始在 index 0&#xff0c;每次可以跳跃的区间是 0-nums[i]保证可以跳到 nums 的末尾&#xff0c;返回跳到末尾的最小步骤 思路 题解是贪心&#xff0c;选择每次可以跳到的最…

上位机知识篇---GitGitHub

文章目录 前言Git&GitHub是什么&#xff1f;GitGitHub Git和GitHub的区别定位功能使用方式开源协作 Git常用命令操作1. 配置2. 仓库操作3. 文件操作4. 分支与合并5.远程操作6.撤销更改7.查看历史 GitHub常用操作1.创建仓库2.Fork仓库3.Pull Request4.Issue跟踪5.代码审查 G…

list容器(详解)

list的介绍及使用&#xff08;了解&#xff0c;后边细讲&#xff09; 1.1 list的介绍&#xff08;双向循环链表&#xff09; https://cplusplus.com/reference/list/list/?kwlist&#xff08;list文档介绍&#xff09; 1. list是可以在常数范围内在任意位置进行插入和删除的序…

Android 开发:新的一年,新的征程

回顾 2023 年&#xff0c;Android 开发领域可谓成果斐然。这一年&#xff0c;Android 系统不断迭代&#xff0c;新技术、新工具层出不穷&#xff0c;为开发者们带来了前所未有的机遇与挑战。如今&#xff0c;我们站在新的起点&#xff0c;怀揣着对技术的热爱与追求&#xff0c;…