Lambda的进阶使用技巧

Lambda的进阶使用技巧

自C++11 起,lambda表达式 逐渐在C++开发中得到使用,在STL中使用了大量的Lambda 表达式。它用以替换独立函数或者函数对象,允许将函数作为另一个函数的参数,并且使代码更可读。利用Lambda表达式的特性,可以极大的提升了编程效率。

Lambda基本结构

[捕获列表] (参数列表) {函数体}

常见捕获参数类型,基本可分为值捕获、捕获引用捕获、指针捕获,这些和函数参数传递类型基本一致,其它捕获类型可根据实际使用情况,可以在具体使用时,直接Google。

  • []:默认不捕获任何变量;
  • [=]:默认以复制捕获所有变量;
  • [&]:默认以引用捕获所有变量;
  • [x]:仅以复制捕获x,其它变量不捕获;
  • [this]:通过引用捕获当前对象(其实是复制指针);
  • [*this]:通过复制方式捕获当前对象;

Lambda与标准库函数

在编写C++代码的过程中,会使用到STL和算法库,这些库与自定义数据结构一起使用时,往往需要开发者实现特定的函数,例如比较函数。使用Lambda 以后可以不依赖具体类型,实现一些通用函数,减少针对特定类型结构的开发工作。例如,下面这个比较函数。

std::vector<Point> point_array = {{4,2}, {1,4}, {2,6}, {7,8}};
std::sort(point_array.begin(), point_array.end(),[](const auto&amp; a, const auto&amp; b) {
            return a.x < b.x || (a.x == b.x &amp;&amp; a.y < b.y);
});

for (int i = 0; i < point_array.size(); ++i){
        std::cout <<point_array[i].x << " " << point_array[i].y << ", ";
}
std::cout << std::endl;
输出结果:1 4, 2 6, 4 2, 7 8
  • 这里没有捕获任何参数,传递了一个包含两个参数的lambda表达式。
  • 在此之前,需要定义一个仿函数才可以实现自定义类型的排序算法,还要考虑函数参数,复杂度较高。
  • GCC 需要支持C++14及以上版本,低版本的GCC 不支持使用auto 自动推演变量类型。

Lambda与多线程

在使用C++开发计算类服务时,往往会使用新线程去异步执行计算逻辑,主线程只需要获取计算结果即可。

int n = 1;
std::promise<int> promise;
std::future<int> future = promise.get_future();
std::thread t([&amp;promise, n](){
     sleep(n);
     promise.set_value(n); });
future.wait();
std::cout << future.get() << std::endl;
t.join();
  • 外层线程创建了一个promise作为参数,同时生成一个future对象,和线程t进行通信。
  • 线程t创建后直接执行lambda表达式,不再需要刻意实现线程函数,考虑线程函数参数类型。
  • lambda捕获局部变量promise,处理完任务以后,向promise中设置处理结果。
  • 外层线程调用wait等待线程t内部设置promise 的值。

在多线程中将lambda 与future/promise机制结合以后,实现多线程处理更加简单、代码可读性更高。

Lambda与线程池

日常开发中,会使用到线程池来实现计算类逻辑,利用Lambda表达式将业务逻辑封住起来,即可实现通用的线程池,提升日常开发效率。

  • 构造Task时可以根据实际需要,捕获不同的处理参数,构造不同的Task,Submit到Task队列。
  • 各个执行线程从队列中取出Task以后,直接执行Task->OnRun() 方法,OnRun内部会调用各个Task的Lambda表达式。
  • 使用Lambda以后,可以实现足够通用的线程池,线程函数不再受函数参数的限制。

适用总结

  • 业务逻辑抽象,例如作为一个framework 需要执行业务逻辑,这个时候就可以将业务逻辑,通过lambda 表达式传递进来。
  • 需要捕获外部变量的逻辑处理,例如异步编程中,启用一个线程独立处理计算任务。
  • 定时任务,执行一些计算逻辑,同时需要获取局部变量、this指针。

2 thoughts on “Lambda的进阶使用技巧

发表评论

邮箱地址不会被公开。 必填项已用*标注