zoukankan      html  css  js  c++  java
  • C++匿名函数lambda

    仿函数std::function

    函数指针与回调函数

    lambda表达式简介

    lambda被设计的主要目的之一就是简化仿函数的使用,使用lambda替代仿函数应该满足一下几个条件:

    • 是局限于一个局部作用域中使用的代码逻辑。

    • 这些代码逻辑需要作为参数进行传递。

    问题

    lambda捕获的变量放在堆上???

    剖析点

    • 值捕获,即使在lambda后面改变了该值,在调用lambda时,这个值还是捕获时的值

    • 引用捕获,在lambda后面改变了该值,在调用lambda时,这个值不是捕获时的值,而是改变后的值

    • 隐式捕获:

    捕获列表 描述
    [=] 代表全部采用值捕获
    [&] 代表全部采用引用捕获
    [=, &val] 代表val为引用捕获,其余为值捕获
    [&, val] 代表val为值捕获,其余为引用捕获
    • 可变lambda,当想在lambda函数体里修改一个值捕获的变量时,需要mutable关键字

    • lambda的返回类型,函数体时单一的return语句的话,可以在声明lambda时,省略返回值的类型

        auto lambda = []()->int {return 100; };  //->int用来说明表达式返回值的类型,可以省略
        std::cout << lambda();
    

    返回值类型后置

    注意点

    • 引用捕获,会引发很多血案。比如:被捕获的引用或者指针的对象已经不存在了,然后调用lambda时就会出现致命的错误。

    • 当以引用或者指针方式捕获一个变量时,必须保证在lambda执行时变量是存在的。

    • 捕获列表和参数列表有区别,捕获列表里的变量,是在捕获的时间点就确定了,而不是在lambda调用时确定,参数列表是在调用时才确定。所以当捕获了一个int i,i=12,然后在lambda后面的代码又改变i为22,但是当调用lambda的时候,i值还是12。

    建议

    • 捕获一个普通变量时,如int, string或其他非指针类型,通常可以采用简单的值捕获方式。所以,只需关注变量在捕获时,值是否是所需的值就行。

    • 如果捕获一个指针、迭代器或引用,就必须保证在lambda被执行的时候,绑定到迭代器、指针或引用的对象仍然存在,而且,需要保证对象是预期的值。因为,有可能在捕获的时候是预期的值,但是在执行lambda之前有代码改变了绑定对象的值,在执行lambda时,就变成不是预期的值了。

    • 一般来说,尽量减少捕获的数据量,来避免潜在的捕获导致的问题。而且,如果可能的话,尽量避免捕获指针或引用。

    代码

    点击查看代码
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    int main()
    {
    	{//test1 值捕获
    		int i = 1;
    		auto f = [i] {return i; }; //等价于 auto f = [i](){return i;};  ()可写可不写
    		i = 10;
    		int j = f();
    		cout << j << endl;  // 1
    	}
    
    	{//test2 引用捕获
    		int i = 1;
    		auto f = [&i] {return i; };
    		i = 10;
    		int j = f();
    		cout << j << endl;  // 10
    	}
                                                        
    	{//test3 隐式值捕获
    		int i = 1;
    		int j = 2;
    		auto f = [=] {return i + j; };
    		i = 3;
    		int m = f();
    		cout << m << endl;  //3
    	}
    
    	{//test4 隐式引用捕获
    		int i = 1;
    		int j = 2;
    		auto f = [&] {return i + j; };
    		i = 3;
    		int m = f();
    		cout << m << endl;  //5
    	}
                                                               
    	{//test5 隐式、显式混合捕获1
    		int i = 1;
    		int j = 2;
    		//i为值捕获,j为引用捕获
    		auto f = [=, &j] {return i + j; };
    		i = 3;
    		j = 4;
    		int m = f();
    		cout << m << endl;  //5
    	}
    
    	{//test5 隐式、显式混合捕获2 
    		int i = 1;
    		int j = 2;
    		//i为引用捕获,j为值捕获
    		auto f = [&, j]()->int {return i + j; };  //->int是C++返回值类型后置语法
    		i = 3;
    		j = 4;
    		int m = f();
    		cout << m << endl;  //5
    	}
    
    	{//test6 可变lambda 1
    		int i = 10;
    		auto f = [&i]/*()mutable*/ {return ++i; }; // 引用捕获mutable可写可不写
    		i = 5;
    		int j = f();
    		cout << j << endl;  //6
    	}
    
    	{//test6 可变lambda 2
    		int i = 10;
    		auto f = [i]()mutable {return ++i; };  // 值捕获必须有mutable,不然报错,此处不能省略()
    		i = 5;
    		int j = f();
    		cout << j << endl;  //6
    	}
    
    	{//值捕获,引用捕获均编译错误,因为i为const
    		//const int i = 10;
    		//auto f = [&i]() mutable {return ++i; };
    		//auto f = [i]() mutable {return ++i; };
    		//int j = f();
    		//cout << j << endl;
    	}
    
    	{// test7 捕获列表和参数列表
    	 // 参数列表是需要在调用该lambda的时候传入参数,捕获列表是用来声明那些变量可以在lambda内部使用
    		int i = 1;
    		auto f = [i](int x) {return -(i + x); }; //参数列表:调用时需要传入一个int值,捕获列表:变量i可以在lambda内部使用
    		auto j = f(3);
    		cout << j << endl;  // -(1+3) = -4
    	}
    
    	//test8 lambda的返回类型  
    	{
    		vector<int> ivec{ -12,2,-22,3,0 };
    		//改变ivec里的值,负数变成正数                                                
    		//此lambda不写返回类型没有问题.                                               
    		transform(ivec.begin(),ivec.end(),ivec.begin(),[](int i){return i < 0 ? -i : i;});
    		                              
    		//此lambda不写返回类型也没有问题.  
    		vector<int> ret;
    		ret.resize(ivec.size());
    		transform(ivec.begin(), ivec.end(), ret.begin(), [](int i) {if (i < 0) return -i; else return i; });
    
    		for (const auto& s : ret)
    		{
    			cout << s << " ";
    		}
    		cout << endl;
    	}
    
    	return 0;
    }
    

    转载:c/c++ lambda表达式剖析

  • 相关阅读:
    _bzoj1061 [Noi2008]志愿者招募【最小费用最大流】
    _bzoj2243 [SDOI2011]染色【树链剖分】
    _bzoj1013 [JSOI2008]球形空间产生器sphere【高斯消元】
    _bzoj1002 [FJOI2007]轮状病毒【瞎搞】
    leetcode 273 Integer to English Words
    leetcode 12 Integer to Roman
    leetcode 1071 Greatest Common Divisor of Strings
    lc6 ZigZag Conversion
    lc13 Roman to Integer
    leetcode 171 Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/mmmmmmmmm/p/14037417.html
Copyright © 2011-2022 走看看