C++笔记 Lambda表达式
Lambda表达式是C11引入的核心特性之一本质是一种匿名函数可以捕获作用域内的变量无需单独定义函数名就能实现简洁、灵活的代码编写尤其适合作为回调函数、算法参数如STL算法等场景大幅提升代码可读性和开发效率。一、Lambda表达式的核心作用Lambda的核心价值的是“轻量、匿名、可捕获”解决了传统函数的两个痛点无需单独定义函数尤其是只使用一次的简单逻辑减少代码冗余可以直接捕获当前作用域的变量局部变量、类成员等无需通过参数传递简化逻辑。最常见的使用场景配合STL算法如sort、for_each、多线程回调如thread、async、条件变量的wait条件判断等。二、Lambda表达式的语法结构必背Lambda的语法格式固定核心由5部分组成其中只有“函数体”是必须的其余部分可根据需求省略[捕获列表] (参数列表) mutable noexcept -gt; 返回值类型 { 函数体; }1. 各部分详解从左到右1捕获列表 [ ]最关键部分控制Lambda能否访问外部变量捕获列表用于指定“Lambda能使用哪些外部变量”有5种常见写法必须牢记捕获方式语法说明空捕获[]不捕获任何外部变量Lambda内部只能使用自身参数和全局变量值捕获[var1, var2]捕获指定变量var1、var2拷贝一份到Lambda内部默认不可修改除非加mutable引用捕获[var1, var2]捕获指定变量的引用Lambda内部操作会直接修改外部变量注意变量生命周期避免悬空引用值捕获所有变量[]捕获当前作用域所有外部变量均为值拷贝默认不可修改引用捕获所有变量[]捕获当前作用域所有外部变量均为引用可修改外部变量注意捕获列表不能混合冲突比如[, var]是允许的所有变量值捕获唯独var引用捕获但[, var]也是允许的所有变量引用捕获唯独var值捕获但[, ]、[var, ]是错误的。2参数列表 ( )和普通函数的参数列表一致用于接收外部传递给Lambda的参数语法和普通函数完全相同可省略当无参数时。// 无参数可省略() auto func1 [] { cout 无参数Lambda endl; }; // 有参数和普通函数一致 auto func2 [](int a, int b) { return a b; };3mutable可选解除值捕获的“只读限制”值捕获的变量默认在Lambda内部是“只读”的无法修改加上mutable后允许修改Lambda内部的拷贝不会影响外部原变量。int x 10; // 错误值捕获x默认不可修改 // auto func [x] { x; }; // 正确加mutable可修改内部拷贝 auto func [x]() mutable { x; cout 内部x x endl; }; func(); // 输出内部x11 cout 外部x x endl; // 输出外部x10原变量未变4noexcept可选声明Lambda不会抛出异常和普通函数的noexcept作用一致用于告诉编译器Lambda内部不会抛出异常可提升性能尤其在多线程、STL算法中常用。auto func [](int a) noexcept { return a * 2; };5返回值类型 - 类型可选编译器可自动推导如果Lambda函数体只有一条return语句编译器会自动推导返回值类型可省略“- 返回值类型”如果函数体有多条语句且有返回值必须显式指定返回值类型。// 自动推导返回值int可省略- int auto add [](int a, int b) { return a b; }; // 必须显式指定返回值否则编译错误 auto func [](int a) - double { if (a 0) return 1.0; else return 0.5; };6函数体 { }Lambda的核心逻辑和普通函数的函数体一致可编写任意合法的C代码可使用捕获的变量、参数列表中的参数。三、Lambda表达式的基本使用示例示例1基础用法无捕获、有参数、自动推导返回值#include iostream using namespace std; int main() { // 定义Lambda计算两个数的和 auto add [](int a, int b) { return a b; }; // 调用Lambda和调用普通函数一样 int result add(3, 5); cout 3 5 result endl; // 输出3 5 8 return 0; }示例2捕获外部变量值捕获引用捕获#include iostream using namespace std; int main() { int x 10, y 20; // 值捕获x引用捕获y auto func [x, y]() { // x是值拷贝不可修改无mutabley是引用可修改 // x; // 错误值捕获默认只读 y; cout 内部x x , 内部y y endl; }; func(); // 输出内部x10, 内部y21 cout 外部x x , 外部y y endl; // 输出外部x10, 外部y21 return 0; }示例3配合STL算法最常用场景Lambda最常用的场景就是作为STL算法的参数替代繁琐的函数对象或全局函数。#include iostream #include vector #include algorithm using namespace std; int main() { vectorint vec {3, 1, 4, 1, 5, 9}; // 1. 用Lambda排序降序 sort(vec.begin(), vec.end(), [](int a, int b) { return a b; // 降序排序规则 }); // 2. 用Lambda遍历输出 for_each(vec.begin(), vec.end(), [](int val) { cout val ; }); // 输出9 5 4 3 1 1 return 0; }示例4配合多线程回调函数#include iostream #include thread using namespace std; int main() { int num 0; // 引用捕获num在子线程中修改 thread t([num]() { for (int i 0; i 10000; i) { num; } }); t.join(); // 等待子线程结束 cout num num endl; // 输出num 10000 return 0; }四、Lambda表达式的注意事项面试高频1. 捕获变量的生命周期问题重点坑引用捕获的变量Lambda内部持有变量的引用如果外部变量生命周期结束比如出作用域销毁Lambda再访问该引用会导致悬空引用程序崩溃。// 错误示例引用捕获局部变量变量销毁后Lambda访问悬空引用 auto getFunc() { int x 10; return [x]() { cout x endl; }; // x是局部变量出函数销毁 } int main() { auto func getFunc(); func(); // 崩溃访问悬空引用 return 0; }解决方案如果Lambda要在外部使用优先使用值捕获拷贝一份不受外部变量生命周期影响。2. Lambda的本质是“函数对象”Lambda在编译时会被编译器自动转换为一个“匿名的函数对象”也叫仿函数因此Lambda可以赋值给std::functionC11的函数包装器方便存储和传递。#include functional #include iostream using namespace std; int main() { // Lambda赋值给function functionint(int, int) add [](int a, int b) { return a b; }; cout add(2, 3) endl; // 输出5 return 0; }3. 捕获列表不能捕获全局变量、静态变量全局变量、静态变量属于全局作用域Lambda内部可以直接访问无需在捕获列表中声明捕获列表只用于捕获“局部变量”。#include iostream using namespace std; int g_val 100; // 全局变量 int main() { static int s_val 200; // 静态变量 // 无需捕获直接访问全局变量、静态变量 auto func []() { cout 全局变量 g_val endl; cout 静态变量 s_val endl; }; func(); // 正常输出全局变量100 静态变量200 return 0; }4. mutable的作用范围mutable只允许修改“值捕获”的拷贝不会影响外部原变量引用捕获的变量即使不加mutable也可以修改因为引用本身就是直接操作原变量。5. Lambda不能递归调用除非借助std::functionLambda是匿名函数自身无法直接调用自己如果需要递归必须先将Lambda赋值给std::function再在函数体中调用该function。#include functional #include iostream using namespace std; int main() { // 先声明function再赋值Lambda functionint(int) factorial; factorial [factorial](int n) { return n 1 ? 1 : n * factorial(n - 1); }; cout factorial(5) endl; // 输出1205的阶乘 return 0; }五、Lambda表达式的核心总结笔记直接抄Lambda是C11匿名函数核心语法[捕获列表](参数列表) mutable noexcept - 返回值类型 {函数体;}捕获列表是核心分5种[]、[var]、[var]、[]、[]不可混合冲突值捕获默认只读需修改内部拷贝加mutable引用捕获需注意变量生命周期返回值可自动推导单条return多条return需显式指定最常用场景STL算法参数、多线程回调、简单逻辑的临时函数本质是函数对象可赋值给std::function支持递归需借助function。Lambda的核心优势是“简洁、灵活”能大幅简化代码尤其在需要临时函数的场景中替代传统函数或函数对象提升代码可读性和开发效率是C多线程、STL开发的必备技能。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2490536.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!