0 前言
最近通过内部换组来到了新的开发组,组里核心业务用的是C++17,并且十分注重性能和资源的优化。我作为一个C++小白,趁着年底没有太多工作、下一年的项目也还没有启动的空档,看代码之外也花了些时间阅读C++书籍,希望能系统地学习这门语言。
最近在看项目代码时发现Lambda表达式在我们的代码中很常见,正好今天在阅读C++ Primer的时候读到了C++ Lambda的介绍,它在用法上和Java很相似,但有一个要素在Java的lambda表达式中很少特意提出来讲,那就是变量的捕获。这篇文章主要是想简单地总结一下C++ Lambda表达示的捕获列表的概念和用法。
1 Lambda表达式简介
在C++在11及之后的版本中支持了lambda表达式,它是一种像函数一样可调用的对象,就和匿名的inline function差不多。一个简单的lambda表达式的主要由返回类型、参数列表、捕获列表和方程体组成,可以表示为
[capture list] (parameter list) -> return type { function body }
关于Lambda表达式的更多内容,我会在以后的文章中多写学习笔记和自己的理解,这里先不赘述,先来看看捕获列表这个概念。
2 捕获列表(Capture List)
尽管Lambda表达式常常会被用在一个函数里,但它只能访问外部的全局变量而并不能访问函数里的局部变量,而这个捕获列表就是这Lambda表达式提供一个函数内的局部变量列表,只要被列在了列表内,那么表达式都可以对其进行访问。Lambda会将这些变量信息和自身放在一起,通常我们把它们这个整体叫作闭包(enclosure)。
一般来说,捕获变量的方式主要有两种:按值捕获(capture by value)和按引用捕获(capture by reference),不同的捕获方式不仅仅是让lambda表达式访问变量的方式不同,还由于它们在编译上的差别,它们对程序的限制也有所不同。这里为了方便也为了和C++ Primer的讲述方式一致,我将它们分为三大类来讲:
- 按值捕获(capture by value)
- 按引用捕获(capture by reference)
- 隐式捕获(implicit captures)
2.1 按值捕获
和传递变量里的传递变量值类型相似,这种捕获方式捕获的也是变量的值,在编译期间,会在Lambda表达式被创建的时候把这个变量复制给局部的一个临时变量,所以这种捕获方式的变量必须是可以被复制的变量。比如在以下的例子中,我们将函数内的整型变量v1
按值放入捕获列表中来让Lambda表达式能够访问其变量值:
#include <iostream>