1.lambda表达式

lanbda表达式简单地来讲就是一个匿名函数,就是没有名称的函数,如果以前有接触过python或者erlang的人都比较熟悉这个,这个可以很方便地和STL里面的算法配合

    std::for_each(list.begin(),list.end(),
[ &tmp,id ](struct ComingVesselInfo *info)
{
if( info->m_nShipID == id)
{
tmp = info;
return ;
}
}
);

这个是我在项目里面使用的一段代码,如果没有lambda,的代码则是这样的:

    for ( auto iter = list.begin();
iter != list.end();
++iter)
{
if ( iter->m_nShipID == id)
{
tmp = iter;
}
}

从上面的代码比较并没有看出lambda有什么用,反而丧失了一点代码的可读性,但是我觉得lambda的引入不是我们可以在函数内直接很方便地写函数,而是可以很好地跟STL algorithm库配合,在我们的项目中,我很少使用到STL algorithm库,因为大部分算法函数都有下面的两个问题:

1.无法获取返回值

2.无法传入其他的参数(比如上面的for_each的例子,如果没有lambda,并没有办法把tmp和id传入)

lambda的引入解决了我在项目中使用STL的algorithm的顾虑

顺便说下,上面的auto也是C++11的新标准,就是自动推导右边数据的类型

2.function和bind以及委托


在C#里面,我们经常会看到使用委托的,C#的委托语法是这样的:

public delegate void Ticket();

这样的话,我们只要声明一个Ticket t,这个只要符合functionname()这个形式的参数,不管是static 函数还是类成员函数,都可以赋值给t,并且可以通过t()来调用该函数或者成员函数

很多学C#的程序员一看这个就简单地把委托认为是C++里面的函数指针,其实这个是错的,委托和函数指针的区别在于,委托是有状态的,更类似与闭包,而函数指针只是一个地址,是没有状态的,单纯的函数指针无法根据我们的需求去传入外部的状态(也就是无法根据需求去改变传入参数的个数和参数的类型)

在C++里面,我们只能通过这样来指向一个成员函数的指针:

int (simple:: *pfn) (int)  = simple::fn;

这样地话我们才能把一个类成员函数指针指向一个类的成员函数,但是这样明显有两个缺点:

1.我们需要在函数调用的时候才能传入参数,无法在函数确定要指向哪一个类成员函数的时候指定参数

2.最重要的一点,我们无法把pfn认识指向一个functionname(int)的类成员函数,我们只能再次定义一个函数指针

在C++里面实际上也是有类似于委托的功能,利用类的成员变量来保存我们的状态,然后重载operator(),就可以达到我们所说的闭包的效果

class Add
{
public:
Add(int i,int j)
{
m_i = i;
m_j = j;
} int operator()()
{
return m_i + m_j;
} protected:
int m_i;
int m_j;
};

这样我们就可以这样使用这个Add类

    Add add(1,2);
cout<<add()<<endl;

但是很明显地,这样做我们每次都需要根据需求去创建一个class,实际上并没有比我们根据需求来写函数方便地多少,还不如直接使用lambda,在C++ 11则解决了这个问题,引入了boost的function和bind

class calc
{
public:
calc(int base)
{
m_base = base;
} int Add(int j)
{
m_base += j;
return m_base;
} int sub(int j)
{
m_base -= j;
return m_base;
}
protected:
int m_base;
};
int main(int argc,char *argv[])
{
calc *c = new calc(10);
tr1::function<int ()> fun; fun = tr1::bind(&calc::Add,c,3);
cout<<fun()<<endl; tr1::function<int (int)> fun2;
fun2 = tr1::bind(&calc::sub,c,tr1::_1);
cout<<fun2(3); }

function和bind的引入解决了我们无法使用C#里面委托的问题,并且既可以提前绑定参数,又可以延后绑定参数,而且可以跟任何类成员函数配合

看起来是很方便的,但是别忘记了C++里面的一个问题,就是C++没有内存回收的功能,如果我们bind的类被释放掉了,那么会怎么样??

如果我们main函数改成下面这样调用:

    calc *c = new calc(10);
tr1::function<int ()> fun; fun = tr1::bind(&calc::Add,c,3);
delete c;
c = NULL; cout<<fun()<<endl;

那么我们调用fun()的时候会发生什么事情??

我们无法得知计算得结果,因为此时的c已经被delete掉了,虽然可以依然正常调用Add函数(如果对C++比较熟悉的应该知道为什么可以正常调用Add),但是内部我们保存的"状态"不见了,也随着delete动作一起消失了,留下的是一串随机的数

但是如果我们把下面的代码改成这样:

tr1::function<int ()> fun2;
{
  calc d(12);
  fun2 = tr1::bind(&calc::Add,d,40);
}

fun2();

那么即使在d释放掉以后,我们依然可以正常地调用fun2

根据我的测试,在我们调用bind的时候,实际上将整个类的当前"状态"都复制了过去,而且在VS2010的平台上,我自己测试了下,调用了9次的复制构造函数,如果我们不好好处理这个,对于性能将会是巨大的损失

当时标准库的设计者也没有那么地傻,所以bind也可以传入指针:

fun2 = tr1::bind(&calc::Add,&d,40);

当然这个又涉及到类的状态保存的问题,类销毁了怎么办??

所以说C++的function和bind的再能模仿,也无法模仿到C#的委托,毕竟C++里面没有人帮我们管理内存,而C#程序员似乎不用关心这些,C++程序员永远离不开内存管理的话题

参考资料:

以boost::function和boost:bind取代虚函数

http://www.boost.org/doc/libs/1_54_0/doc/html/function.html

http://www.boost.org/doc/libs/1_54_0/libs/bind/bind.html

http://msdn.microsoft.com/zh-cn/library/vstudio/dd293608.aspx

学习C++11的一些思考和心得(1):lambda,function,bind和委托的更多相关文章

  1. Ext.Net学习笔记11:Ext.Net GridPanel的用法

    Ext.Net学习笔记11:Ext.Net GridPanel的用法 GridPanel是用来显示数据的表格,与ASP.NET中的GridView类似. GridPanel用法 直接看代码: < ...

  2. SQL反模式学习笔记11 限定列的有效值

    目标:限定列的有效值,将一列的有效字段值约束在一个固定的集合中.类似于数据字典. 反模式:在列定义上指定可选值 1. 对某一列定义一个检查约束项,这个约束不允许往列中插入或者更新任何会导致约束失败的值 ...

  3. golang学习笔记11 golang要用jetbrain的golang这个IDE工具开发才好

    golang学习笔记11   golang要用jetbrain的golang这个IDE工具开发才好  jetbrain家的全套ide都很好用,一定要dark背景风格才装B   从File-->s ...

  4. Spring MVC 学习笔记11 —— 后端返回json格式数据

    Spring MVC 学习笔记11 -- 后端返回json格式数据 我们常常听说json数据,首先,什么是json数据,总结起来,有以下几点: 1. JSON的全称是"JavaScript ...

  5. Python3+Selenium3+webdriver学习笔记11(cookie处理)

    #!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记11(cookie处理)'''from selenium im ...

  6. 并发编程学习笔记(11)----FutureTask的使用及实现

    1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...

  7. 《C++ Primer Plus》学习笔记11

    <C++ Primer Plus>学习笔记11 第17章 输入.输出和文件 <<<<<<<<<<<<<< ...

  8. SpringMVC:学习笔记(11)——依赖注入与@Autowired

    SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...

  9. 零基础学习前端1-1配置node及npm环境变量

    零基础学习前端1-1配置node及npm环境变量 ## 1-1配置node及npm环境变量 首先:下载node 可以直接去官方网站下载 1.首先从官网下载安装包 https://nodejs.org/ ...

随机推荐

  1. 利用.htaccess绑定子域名到子目录(亲测万网可用)

    http://www.xmgho.com/archives/783.html  利用.htaccess绑定域名到子目录,前提你的空间服务器必须支持apache的rewrite功能,只有这样才能使用.h ...

  2. Python 结巴分词

    今天的任务是对txt文本进行分词,有幸了解到"结巴"中文分词,其愿景是做最好的Python中文分词组件.有兴趣的朋友请点这里. jieba支持三种分词模式: *精确模式,试图将句子 ...

  3. archlinux下查看机器的ip地址

    问题原因 默认archlinux没有安装ifconfig这个在其它发行版中常用的命令,刚开始不知道怎么查看机器的ip. 解决方案 使用archlinux中已经安装的ip命令.在后面跟上addr, ro ...

  4. dennis gabor 从傅里叶(Fourier)变换到伽柏(Gabor)变换再到小波(Wavelet)变换(转载)

    dennis gabor 题目:从傅里叶(Fourier)变换到伽柏(Gabor)变换再到小波(Wavelet)变换 本文是边学习边总结和摘抄各参考文献内容而成的,是一篇综述性入门文档,重点在于梳理傅 ...

  5. Spring事务配置的五种方式 -- 越往后需要Spring版本越高

    第五种 基本零配置  个人感觉第四种也可以 Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式, ...

  6. ros与下位机通信常用的c++ boost串口应用--22

    摘要: 原创博客:转载请表明出处:http://www.cnblogs.com/zxouxuewei/ 一.首先移植c++ boost 库: 1. 先去 Boost官网 下载最新的Boost版本, 我 ...

  7. python爬虫抓网页的总结

    python爬虫抓网页的总结 更多 python 爬虫   学用python也有3个多月了,用得最多的还是各类爬虫脚本:写过抓代理本机验证的脚本,写过在discuz论坛中自动登录自动发贴的脚本,写过自 ...

  8. Docker网络管理

    一.Docker的四种网络模式(host.container.none.bridge) 1. host模式,使用docker run时使用--net=host指定,docker使用的网络实际上和宿主机 ...

  9. Java——交通灯

     /* * 交通灯管理系统的 项目需求: * 模拟实现:  十字路口的交通灯系统逻辑,  具体需求如下: *  异步随机生成按照各个路线行驶的车辆. *  信号灯忽略黄灯.  只考虑红灯和绿灯. ...

  10. mysql+mybatis 插入可递增字段库表操作

    mysql本身类型介绍: BIGINT 8 字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) (0,18 446 744 073 70 ...