关于 C++11 Lambdas

本文详细介绍了C++11中的Lambda函数,包括其定义、使用场景和示例。Lambda函数作为匿名函数,常用于回调,能简化代码并减少函数指针带来的开销。文章讨论了不同类型的捕获方式,如按值、按引用以及混合方式,并提醒了在使用Lambda时需要注意的范围问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lambdas

本文将介绍什么是Lambdas函数及如何使用Lambdas函数。

什么是Lambdas函数

Lambda函数是C ++中的一种匿名函数,主要用作C ++中的回调,它主要在我们必须创建非常小的函数以作为回调传递给另一个API时使用。

使用场景和示例

假设现在我有一个整数数组,我想遍历此数组并使用STL算法for_each打印所有元素。

首先让我们使用函数指针来做到这一点,

void display(int a){
	std::cout << a << endl;
}
void demo0(){
	vector<int> ary({ 1, 2, 3, 4, 5 });
	for_each(ary.begin(), ary.end(), &display);
	return;
}

在上面的示例中,为了进行简单显示,我们创建了一个单独的函数,从而造成了一定的开销。若要解决此问题,可以使用lambda函数。Lambda函数是一种匿名函数,它没有名称,但是您可以传递参数并从中返回结果。同样,其所有内容都将用作内联代码。

lambda函数的示例:

[](int i){
	cout << i << endl;
}

以上示例中,

  • []用于传递外部作用域元素
  • (int i)用于传递参数x

demo0() 升级为lambda函数的示例:

void demo1(){
	vector<int> ary({1,2,3,4,5});
	for_each(ary.begin(), ary.end(), [](int i){
		cout << i << endl;
	});
	return;
}

将外部的元素传进Lambda函数中

情况一:使用[=]

[=](int &x) {
  //所有外部范围元素都是按值传递的
}

情况二:使用[&]

[&](int &x) {
  //所有外部范围元素都是通过引用传递的
}

通过下面的示例,可以看出如何在lambda函数内部使用外部范围元素。

void demo2(){
	vector<int> ary({ 1, 2, 3, 4, 5 });
	int value = 0;

	for_each(ary.begin(), ary.end(), [&](int i){
		//可以修改value,因为对所有外部作用域元素都有写访问权限。
		value += i;
	});
	cout << value << endl;	//15

	for_each(ary.begin(), ary.end(), [=](int i){
		//不能修改value,因为所有外部作用域元素在这里都有只读访问权限。
		cout << value << endl;	//允许读
		//value += i;			//编译时错误
	});
	
	for_each(ary.begin(), ary.end(), [](int i){
		//不能访问value,因为所有外部作用域元素在这里都不可见。
		//cout << value << endl;	//编译时错误
	});

	return;
}

捕获指定外部变量

一个简单的Lambda语法是

[Captured variables](paameters) { function code }

外部作用域的局部变量可以在Lambda内部以两种模式捕获,即值传递和引用。

  • 按值捕获局部变量

    要通过值捕获局部变量,可在捕获列表中指定它们的名称,即:

    void demo3(){
    	int v1 = 0;
    	string s1 = "0";
    	auto func = [v1, s1](){
    		cout << v1 << s1 << endl;
    		// v1 = 1;		//编译时错误
    		// s1 = "1";	//编译时错误
    	};
    	func();
    	return;
    }
    

    在lambda内部,可以访问但不能更改它们,因为它们是const。但是,我们也可以通过添加mutable关键字来运行在在lambda表达式中修改。但是,它们的修改不会影响外部作用域变量的值,因为它们是按值捕获的。例如。

    void demo3(){
    	int v1 = 0;
    	auto func = [v1]() mutable{
    		v1 = 1;
    	};
    	func();
    	cout << v1 << endl;	//0
    	return;
    }
    
  • 通过引用方式捕获局部变量

    要通过引用捕获局部变量,可在捕获列表中以前缀&指定它们的名称。

    void demo4(){
    	int v1 = 0;
    	auto func = [&v1](){
    		v1 = 1;
    	};
    	func();
    	cout << v1 << endl;	//1
    	return;
    }
    

    现在,捕获列表中指定的变量将通过引用方式捕获到lambda中。在lambda内部,可以访问它们,还可以更改其值。同样,由于它们是通过引用捕获的,因此它们的修改将影响外部作用域变量的值。

  • 混合方式捕获

    按值捕获全部外部局部变量,但是counter以引用方式捕获

    auto func = [=, &counter] () mutable {};
    

在类中使用Lambda函数

要在Lambda函数中捕获成员变量,需要以按值方式捕获this指针。在lambda函数中捕获this指针将自动在lambda中捕获该对象的所有成员变量。

class Demo{
	int value;
public:
	Demo(){
		auto func = [this](){
			this->value = 1000;
		};
		func();
		cout << value << endl;
	}
};

注意事项

如果在lambda中我们是按引用捕获局部变量,那么我们需要确保在访问或调用lambda函数时,所有按引用捕获的局部变量仍在范围内。

如果lambda将尝试访问或修改按引用捕获的局部变量,而该局部变量不再在范围内,即由于堆栈展开而被破坏,则可能会发生崩溃。例如:

function<void()> getCallBack(){
	int counter = 10;
	auto func = [&counter]() mutable {
		cout << "Before modify: "<<counter << endl;
		counter = 20;
		cout << "After modify:  "<<counter << endl;
	};
	return func;
}
void demo5(){
	auto func = getCallBack();
	func();
	return;
}

输出结果:

Before modify: -858993460
After modify:  20

在这里,我们尝试访问由于堆栈展开而已被破坏的变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值