十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C++ Lambda 表达式完全指南

C++ Lambda 表达式完全指南 一、Lambda 表达式是什么LambdaLambda表达式是 C11 一个非常重要的新特性。很多刚学 C 的人第一次看到[](){};都会觉得很奇怪。其实它没那么神秘。一句话理解Lambda 就是一种“匿名函数”也就是没有名字的函数可以像变量一样传递。二、为什么需要 Lambda先看以前 C 的写法。假设我们有一个数组#include algorithm #include vector std::vectorint nums {1, 2, 3, 4, 5};现在想把所有数字乘 2。以前可能写int Double(int x) { return x * 2; } std::transform( nums.begin(), nums.end(), nums.begin(), Double );问题这个函数只用一次。但是你为了它int Double(int x)专门写了一个函数。如果项目里有很多这种“小功能”会产生大量垃圾函数。于是 C11 引入 Lambdastd::transform( nums.begin(), nums.end(), nums.begin(), [](int x) { return x * 2; } );这个[](int x) { return x * 2; }就是 Lambda。它没有名字但是能执行。三、Lambda 的基本格式Lambda 长这样[capture](parameters) - return_type { function_body };拆开[]捕获列表()参数列表-返回类型可省略编译器自动推导{}函数体例如[](int a, int b) - int { return a b; }等价于int Add(int a, int b) { return a b; }区别普通函数有名字 AddLambda没有名字四、最简单的 Lambda1. 无参数[]() { std::cout Hello Lambda; };调用auto func []() { std::cout Hello; }; func();输出Hello注意Lambda 本身也是一个对象。所以auto func可以保存它。五、Lambda 为什么叫匿名函数因为void Hello() {}有名字Hello而[]() {}没有名字。所以叫Anonymous Function匿名函数。六、Lambda 最重要的部分捕获列表 []这个是面试重点。看例子int x 10; auto func [] { cout x; };编译错误。为什么因为 Lambda 默认不能访问外面的变量。需要告诉它“我要把外面的东西拿进来。”这就是捕获。七、值捕获 []int x 10; auto func []() { cout x; }; func();输出10意思把外部变量复制一份给 Lambda。类似class Lambda对象 { int x; public: void operator()() { cout x; } };实际上 Lambda 底层就是类似一个匿名类。八、引用捕获 []int x 10; auto func []() { x; }; func(); cout x;输出11为什么因为 Lambda 保存的是引用。类似int ref x;所以修改的是外面的 x。九、指定捕获可以只捕获某几个变量。例如int a 10; int b 20; auto func [a, b]() { cout a; cout b; };意思a复制b引用十、捕获总结写法含义[]不捕获任何外部变量[]值捕获所有变量[]引用捕获所有变量[x]值捕获 x[x]引用捕获 x[, x]默认值捕获x 引用捕获[, x]默认引用捕获x 值捕获十一、Lambda 底层原理面试官可能问Lambda 底层怎么实现答案Lambda 本质上是编译器生成的一个匿名类对象通过重载operator()实现函数调用。例如int x 10; auto func [x]() { cout x; }; func();编译器大概生成class Lambda { private: int x; public: Lambda(int value) : x(value) {} void operator()() { cout x; } }; Lambda func(x); func();所以func();实际上调用func.operator()();十二、Lambda 为什么能传给 STL 算法例如sort(nums.begin(), nums.end(), [](int a, int b) { return a b; });第三个参数需要一个比较函数。以前现在[](int a, int b) { return a b; }Lambda 对象拥有operator()所以它可以像函数一样调用。十三、Lambda 的 mutable看int x 10; auto f [x]() { x; };错误。为什么因为值捕获默认是 const。Lambdaoperator() const不能修改自己的成员变量。如果想修改auto f [x]() mutable { x; };现在f();可以。但是注意修改的是 Lambda 内部副本。外面的 xcout x;仍然是10。十四、Lambda 和智能指针结合例如std::shared_ptrPlayer player; auto func [player]() { player-Attack(); };这里Lambda 捕获了一份 shared_ptr。引用计数增加。Lambda 生命周期结束引用计数减少。这在UE 回调、网络异步、多线程里面非常常见。十五、实际项目中的例子UE/C 很常见比如延迟执行TimerManager.SetTimer( Handle, [] { UE_LOG(LogTemp, Warning, TEXT(Timer)); }, 1.0f, false );这里[] { // ... }就是一个回调函数。
返回列表