lambda表达式
等价于匿名函数对象,又称为“闭包”(closure),更便捷,表达更直接。表达式要素包括:
1:捕获列表
2:参数列表
3:mutable修饰符,表达传值或传引用
4:noexcept
5:返回值类型声明 ->
6:表达式体{...}
lambda表达式可接受参数,可返回值,可模板化,也可以通过传值或传引用从闭包范围内访问变量。
编译器将lambda表达式编译为具名函数对象
捕获列表
lambda表达式,从闭包作用域捕获变量而获得状态,分为传值和传引用。
捕获变量登记与函数对象中的示例数据成员。
[=] 值捕获所有变量
[&] 引用捕获所有变量
[&x] 引用捕获x变量
[x] 值捕获x
[=,&x] 默认值捕获,x变量通过引用捕获
[&,x] 默认引用捕获,x通过值捕获
[this] 捕获当前对象,可访问所有共有成员,C++20中不允许隐式捕获this
[=,x],[&,&x] 错误,重复指定
注意:即便默认要值捕获,全局变量总是使用引用捕获
使用初始化捕获表达式表达move捕获
示例及分析
#include <iostream>
#include <vector>
using namespace std;
class Point{
public:
double x;
double y;
void print() const {
std::cout << x<< ", "<<y<<endl;;
}
};
int number=100;
int main()
{
Point p1{100,200};
Point p2{100,200};
auto lambda1 = [=] (int n) mutable
{
p1.x+=n;
p1.y+=n;
p2.x+=n;
p2.y+=n;
p1.print();
p2.print();
number++;
};
lambda1(10);
lambda1(10);
p1.print();
p2.print();
cout<<sizeof(lambda1)<<endl;
cout<<sizeof(Point)<<endl;
cout<<"lambda1------------"<<endl;
auto lambda2 = [&] (int n)
{
p1.print();
p2.print();
p1.x+=n;
p1.y+=n;
p2.x+=n;
p2.y+=n;
number++;
};
lambda2(100);
p1.print();
p2.print();
p1.x+=5;
p1.y+=5;
p2.x+=5;
p2.y+=5;
lambda2(100);
cout<<number<<endl;
cout<<sizeof(lambda2)<<endl;
cout<<"lambda2------------"<<endl;
auto lambda3 = [=, &p1] ()
{
p1.x++;
p1.y++;
p2.print();
};
lambda3();
auto lambda4 = [ &, p1] ()
{
p1.print();
p2.x++;
p2.y++;
};
lambda4();
auto lambda5 = [p2] ()
{
p2.print();
};
lambda5();
auto lambda6 = [&p1] ()
{
p1.x++;
p1.y++;
};
lambda6();
}
捕获原理
//引用lambda内存模型,表达式内部p1,p2就是外部的p1,p2
//引用就是同一个地址,本质就是一个别名
struct Lambda_Ref{
//引用就是一个指针,就是8byte,引用的大小固定了
Point& p1; //生命周期不好管理
Point& p2;
Lambda_Ref( Point& p1, Point& p2):p1(p1),p2(p2)
{
}
void operator()(int n) {
p1.x+=n;
p1.y+=n;
p2.x+=n;
p2.y+=n;
}
};
//值捕获生成的代码
struct Lambda_Value{
Point p1;
Point p2;
Lambda_Value(const Point& p1, const Point& p2):p1(p1),p2(p2) //传值,拷贝
{
}
void operator()(int n) {
p1.x+=n;
p1.y+=n;
p2.x+=n;
p2.y+=n;
}
};
编译、结果输出
kongcb@tcu-pc:~/testcode/lambda$ g++ lamba_capture.cpp -o lamba_capture
kongcb@tcu-pc:~/testcode/lambda$ ./lamba_capture
110, 210
110, 210
120, 220
120, 220
100, 200
100, 200
32
16
lambda1------------
100, 200
100, 200
200, 300
200, 300
205, 305
205, 305
104
16
lambda2------------
305, 405
306, 406
306, 406