【C++八股题整理】lambda表达式(匿名函数)

lambda表达式(匿名函数)

lambda表达式的定义?

[capture](parameters) -> return_type { function_body };
// e.g. [](int a, int b)->int { return a+b; };
// e.g. []{ return 666; };
// e.g. [a](int b) { return a+b; };
  • [capture] 捕获列表:lambda表达式所在函数中定义的局部变量的列表,不可省略
    • 分为值捕获引用捕获
    • [ ]:默认不捕获任何列表
    • [=]:默认以值捕获所有变量
    • [&]:默认以引用捕获所有变量
    • [=, &x]:默认以值捕获所有变量,但是x是例外,通过引⽤捕获
    • [&, x]:默认以引⽤捕获所有变量,但是x是例外,通过值捕获
  • (parameters) 参数列表:和普通函数的参数列表相同。如果不需要参数,可以省略
  • return_type 返回类型:指定返回类型。可以省略,省略时编译器推断返回类型
  • { function_body } 函数体:实际执行的代码,只能使用捕获列表和参数列表中的变量,不可省略

lambda表达式的使用场景?

// 使用场景1:内嵌于函数体
void func(){
	auto f = [](int a, int b)->int { return a+b; };
	cout << f(1,2) << endl; // 3
}
// 使用场景2:内嵌于函数的参数列表
int val = 3;
vector<int> v {1, 8, 5, 3, 6, 10};
int count = std::count_if(v.beigin(), v.end(), [val](int x) { return x > val; });	// v中大于3的元素数量

lambda表达式的优缺点?

  • 优点
    • 可以在函数内部定义lambda表达式,因此其定义和使用是在同一个地方进行的,不像函数一样定义和使用间隔很远
    • lambda表达式可以理解为一个匿名的内联函数,它相比非内联的函数,能避免函数调用时的栈操作,因此提高效率
  • 缺点
    • 难以调试,由于 Lambda 表达式在底层被转换为匿名类,编译器生成的错误信息有时可能不太直观

lambda表达式的底层实现?

编译器实现 lambda 表达式大致分为一下几个步骤:

  • 创建 lambda匿名类,实现构造函数,使用 lambda 表达式的函数体重载operator()(所以 lambda 表达式 也叫匿名函数对象)
  • 创建 lambda 对象
  • 通过对象调用 operator()
// lambda表达式
[a, &b](int c) { return a + b + c; }

// 翻译后的类代码
class Lambda_xxxx {
private:
    int a;      // 按值捕获的成员变量
    int& b;     // 按引用捕获的成员变量

public:
    // 构造函数,用于初始化捕获的变量
    Lambda(int a_, int& b_) : a(a_), b(b_) {}

    // 函数调用运算符
    int operator()(int c) const {
        return a + b + c;
    }
};

lambda表达式的内存大小?

  • 捕获列表为空,lambda表达式等价于一个函数,内存大小通常为1
  • 捕获列表非空,lambda表达式被翻译为匿名类的对象,内存大小与类对象的大小一致。注意,引用捕获的变量,存储的是它的地址,因此大小为一个指针的大小(32位系统4,64位系统8)
int a = 1;
auto f0 = [](){ return 0;};
auto f1 = [&a](){ return a;};
auto f2 = [a](){ return a;};
cout << sizeof(f0) << endl;	// 1
cout << sizeof(f1) << endl;	// 4 int的大小
cout << sizeof(f2) << endl; // 4或8 指针的大小

捕获的变量,是在什么时候赋值?

捕获的变量,是在lambda表达式创建时赋值,而不是在lambda表达式执行时赋值。
看lambda表达式的底层实现就能明白,lambda表达式创建对于类的构造函数,执行对于调用operator()。

int a=1;
auto f1 = [=](){ return a;};
auto f2 = [&](){ return a;};
a=2;
cout << f1() << endl;	// 1
cout << f2() << endl;	// 2

引用捕获的变量,要注意什么?

当以引用方式捕获一个变量时,要保证在lambda表达式执行时,变量的生命周期没有结束。

int *a = new int(1);
auto f = [&](){ return *a;};
delete a;
cout << f() << endl;	// error
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值