2026/1/9 11:06:22
网站建设
项目流程
网站开发团队职能,上海建设安检站网站,俄语网站设计,家用电器网页设计实训报告目录
定义
语法结构
常见捕获列表
常见使用场景
Lambda的本质
Lambda的发展和问题 定义
C中的Lambda表达式是C11引入的新特性#xff0c;允许在代码中定义匿名函数。简单而言#xff0c;他就是一个匿名函数对象#xff0c;通常用于简单、不需要复用、或者需要访问当前…目录定义语法结构常见捕获列表常见使用场景Lambda的本质Lambda的发展和问题定义C中的Lambda表达式是C11引入的新特性允许在代码中定义匿名函数。简单而言他就是一个匿名函数对象通常用于简单、不需要复用、或者需要访问当前上下文变量的场景。语法结构Lambda表达式完整语法如下[捕获列表](参数类型) mutable 异常属性 - 返回类型 {函数体}[捕获列表]这时Lambda核心。它定义了Lambda表达式函数体内部可以访问外部作用域中哪些变量以及如何访问。(参数类型)相当于正常函数的参数列表。mutable可选。默认情况下通过“值捕获”进来的变量都是只读的const。加上mutable后才可以修改他们。但注意这里修改的是Lambda内部的拷贝值外部值并不会实际修改。可以理解为正常情况下形参加了const修饰加入mutable形参没有const修饰但仍是形参。异常属性绝大多数指的是noexcept这个之前聊过就是向编译器和程序员承诺这个函数不会抛出异常常用于性能优化时添加。编译器优化生成更精简的指令移动语义实现“移动数据”而不是“拷贝数据”。- 返回类型。这相当于显示告知编译器该函数的返回类型但一般可省略因为编译器会根据返回的值自动推导出返回类型和auto类似。常用于编译器推导不出、强制类型转换和返回引用时Lambda默认返回的是“值”拷贝。大部分情况下都会是[捕获列表] mutable根据需要参数类型{函数体}的形式异常属性和- 返回类型都是省略不写的。常见捕获列表写法含义[]不捕获任何外部变量。[]值捕获所有外部变量Lambda 内持有的是副本只读。[]引用捕获所有外部变量Lambda 内操作的是本体可读写。[x]只值捕获变量x不捕获其他。[x]只引用捕获变量x不捕获其他。[, y]默认值捕获所有但变量y引用捕获。[, x]默认引用捕获所有但变量x值捕获。[this]捕获当前类的this指针让 Lambda 能访问类的成员变量/函数。常见使用场景1.场景一配合STL一起使用。#includevector #include iostream int main() { std::vectorint v {4, 3, 2, 1, 5}; std::sort(v.begin(), v.end()); //默认情况下是从小到大排序 for (int i : v) { std::cout i ; } std::cout std::endl; //使用Lambda表达式进行自定义排序 std::sort(v.begin(), v.end(), [](int a, int b) { return a b; // 从大到小排序 }); for (int i : v) { std::cout i ; } std::cout std::endl; return 0; }2.场景二捕获外部变量同时不想传一堆参数时。#includevector #include iostream int main() { std::vectorint v {4, 3, 2, 1, 5}; std::sort(v.begin(), v.end()); int value 2; //通过Lambda找出第一个大于2的元素 auto it std::find_if(v.begin(), v.end(), [value](int x) { return x value; }); if (it ! v.end()) { std::cout First number value is *it std::endl; } return 0; }3.场景三mutable关键字的使用。#include iostream int main() { int x 5; // 按值捕获 x。如果没有 mutable x 会报错 auto f [x]() mutable { x; std::cout x Value: x std::endl; }; f(); f(); std::cout Outside: x std::endl; // 输出 Outside: 5 (外部变量未变) return 0; }Lambda的本质在C编译器眼中Lambda表达式本质是一个匿名的“仿函数”对象。例如当写下以下代码时int a 10; auto f [a](int x) { return a x; };编译器会自动生成匿名类类似于class __AnonymousLambda { private: int m_a; // 对应捕获列表 [a] public: __AnonymousLambda(int a) : m_a(a) {} // 构造函数 // 对应函数体参数列表 int operator()(int x) const { return m_a x; } };这就是为什么Lambda可以拥有状态也可以当作参数传递。Lambda的发展和问题C14增强了Lambda表达式允许在参数列表中使用auto使得lambda更加灵活类似于模版函数如下所示auto add [](auto x, auto y) { return x y; } std::cout add(1, 2) std::endl; // int相加输出 3 std::cout add(1.5, 2.5) std::endl; // double相加输出 4.0 std::cout add(std::string(Hi ), C); // string相加同时在使用Lambda时要注意可能出现的问题Lambda的生命周期。当使用了引用捕获而Lambda的生命周期长于被捕获变量的生命周期比如在一个函数中返回了一个 Lambda该 Lambda 引用了函数内的局部变量这会导致悬垂引用进而引发程序崩溃。错误实例如下std::functionvoid() getPrinter() { int value 42; // 错误引用捕获了局部变量 value // 当 getPrinter 返回时value 被销毁Lambda 内部持有了无效引用 return []() { std::cout value std::endl; }; }这种情况下将引用捕获[]改成值捕获[]或者[value]即可。