• 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表达式剖析

  • 相关阅读:
    洛谷P2516 [HAOI2010]最长公共子序列 动态规划 容斥原理
    [LeetCode]235. Lowest Common Ancestor of a Binary Search Tree
    [LeetCode]144. Binary Tree Preorder Traversal二叉树前序遍历
    [LeetCode]129. Sum Root to Leaf Numbers路径数字求和
    [leetcode]645. Set Mismatch
    [leetcode]110BalancedBinaryTree平衡二叉树
    [leetcode]199. Binary Tree Right Side View
    [LeetCode]116. Populating Next Right Pointers in Each Node
    [leetcode]720. Longest Word in Dictionary字典中最长的单词
    [LeetCode]690. Employee Importance员工重要信息
  • 原文地址:https://www.cnblogs.com/mmmmmmmmm/p/14037417.html
Copyright © 2020-2023  润新知