lambda 表达式 剖析

## 大前提:捕获列表里变量的确定时机。

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

## 剖析点:

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

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

3,隐式捕获:

  • [=]代表全部采用值捕获
  • [&]代表全部采用引用捕获
  • [=, &val]代表val为引用捕获,其余为值捕获
  • [&,val]代表val为值捕获,其余为引用捕获

4,可变lambda,当想在lambda函数体里,修改一个值捕获的变量是,需要mutable关键字。

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

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

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

建议:

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

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

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

#include <iostream>
#include <vector>
#include <algorithm> using namespace std; int main(){
//test1 值捕获
/*
int i = 1;
auto f = [i]{return i;};
i = 10;
int j = f();
cout << j << endl;
*/ //test2 引用捕获
/*
int i = 1;
auto f = [&i]{return i;};
i = 10;
int j = f();
cout << j << endl;//3
*/ //test3 隐式值捕获
/*
int i = 1;
int j = 2;
auto f = [=]{return i + j;};
i = 3;
int m = f();
cout << m << endl;
*/ //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;
int m = f();
cout << m << endl;//3
*/ //test5 隐式,显式混合2
/*
int i = 1;
int j = 2;
//i为引用捕获,j为值捕获
auto f = [&,j]{return i + j;};
i = 3;
int m = f();
cout << m << endl;//5
*/ //test6 可变lambda
/*
int i = 10;
auto f = [i] () mutable{return ++i;};
int j = f();
cout << j << endl;
*/
/*
const int i = 10;
//编译错误,因为i为const
auto f = [i] () mutable{return ++i;};
int j = f();
cout << j << endl;
*/ //test7 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不写返回类型也没有问题.
transform(ivec.begin(),ivec.end(),ivec.begin(),
[](int i){if(i < 0) return -i;
else return i;});
for(const auto &s : ivec){
cout << s << " ";
}
cout << endl;
}

c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854

c/c++ lambda 表达式 剖析的更多相关文章

  1. C++11新特性(3) lambda表达式(1)

    C++11加入了一项名为lambda表达式的新功能.通过这项功能能编写内嵌的匿名函数,而不必编写独立函数或函数对象,使得代码更加理解. lambda表达式包括下面部分. [capture_block] ...

  2. Lambda表达式(C语言-gcc编译器)

    前言 先来啰嗦几句,身边的朋友,同事都喜欢在博客上记录自己在学习计算机编程技术路程上的一些问题和心得.就我个人而言,这是个好习惯,特别是在计算机编程领域,技术方向种类繁多,永无止境.所以,我也开始我人 ...

  3. java8 Lambda表达式的新手上车指南(1)

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

  4. java8 Lambda表达式的新手上车指南(1)--基础语法和函数式接口

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

  5. 浅入浅出Lambda表达式

    大家在开发中会经常看到也会经常使用lambda表达式. 园子里也有很多详解lambda表达式的文章,多是从横向来讲述. 但lambda表达式到底如何变成现在这个样子,表达式的形式到底代表什么含义,这些 ...

  6. c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)

    c#封装DBHelper类   public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...

  7. 你知道C#中的Lambda表达式的演化过程吗?

    那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...

  8. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  9. 背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

随机推荐

  1. Go Web:数据存储(2)——CSV文件

    存储到CSV文件中 1.内存存储 2.CSV文件存储 3.gob序列化存储 本文接上一篇:内存存储. 关于CSV文件的说明,见csv文件格式 当数据存储到了内存中,可以在需要的时候持久化保存到磁盘文件 ...

  2. zend studio快捷键

    某些快捷键会失效,多尝试就好.快捷键就是一种减轻工作量的方式,或者说展示码农码代码的熟练度,重要的还在于对一个问题的看法和角度,说的具体些就是算法和数据结构,不看会后悔,不学设计模式也会吃亏. 应用场 ...

  3. C#通过虚方法实现方法重写—多态。

    class Program { //希望person存的是哪个类的对象就调用哪个类的方法 //第一步 将父类中对应方法家virtual关键字 变为虚方法(子类可重写) //子类中方法用override ...

  4. 分页Sql语句

    第一种 Top剔除法.去除Top (pageIndex-1)*PageSize * FROM dbo.SBD_EXCHANGE_BILL ) EB_ID FROM dbo.SBD_EXCHANGE_B ...

  5. 在Prism 框架中,实现主程序与模块间 UI 的通信

    背景: 在模块的UI中包含 TreeView 控件,在该树形控件的每一节点前面定义了一个复选框,如图 需求: 在两个不同的应用程序中使用该控件,而它在不同应用程序中的外观则并不一致,按照本例,即一个显 ...

  6. Spring Security Oauth2 示例

    所有示例的依赖如下(均是SpringBoot项目) pom.xml <dependencies> <dependency> <groupId>org.springf ...

  7. js如何发送wss协议的请求,以及接受服务器返回的数据

    今天遇到问题,以往都是请求http协议的url,现在请求变成了wss的,用以前那种ajax的方式不可以发送和接受.然后查阅相关资料解决了这个问题,在这记录一下解决办法,使用的是websocket. & ...

  8. angular分页插件tm.pagination 解决触发二次请求的问题

    angular分页插件tm.pagination(解决触发二次请求的问题) DEMO:  http://jqvue.com/demo/tm.pagination/index.html#?current ...

  9. 使用Vue-Router 2实现路由功能

    转自:http://blog.csdn.net/sinat_17775997/article/details/54710420 注意:vue-router 2只适用于Vue2.x版本,下面我们是基于v ...

  10. python里文件读写操作

    文件读写操作一种基本操作,但是里面也存在很多需要注意的问题,例如字符编码.内存缓冲.指针位置等等.如果忽视这些问题就会引起很多不必要的麻烦.简单来说,文件的读写分为几个过程: 打开文件,并定义操作文件 ...