C++ lambda函数在程序开发中作用体现

开发 后端
C++ lambda函数的运用,可以令声明式的编程和运算法则变得更加简单,方便。可以让编程人员以一种灵活的方式来实现程序的开发。

作为一个编程人员,在运用一个语言进行程序开发时,都想通过各种办法来提高自己程序的性能以及提高编程效率。那么在C++语言中,又该如何操作呢?我们在这里为大家介绍的额C++ lambda函数,就是一个可以使代码性能有较大提升的函数。#t#

使编译器以及操作系统从正在创建的应用中榨取更高性能的关键在于提供充足的有关代码意图的信息。在充分了解这个代码意图实现的功能等信息的情况下, 就有可能将代码在编译时和运行时的并行吞吐量最大化,令开发者可以将更多精力放在他们所关注的商业领域的问题,将重量级的多核多处理器的任务计划交托给编 译器,运行时库以及操作系统中的基础设施代码来处理。

循环函数是很重要的一个环节,因为在所有可用的硬件资源中,被分离的循环中的各个部分在一般情况下能够提供更高的应用性能。考虑这样一个小情况:迭代选定组合中的全部元素以求得总和。最简单最直接的执行方法如下:

 

  1. std::vector< int> v;  
  2. v.push_back(1);  
  3. v.push_back(5);  
  4. int total = 0;  
  5. for (int ix = 0; ix <  v.size(); ++ix){  
  6. total += v[ix];  

 

以上的例子十分便于人工读写。对于熟悉C语言家族语法的开发者而言,这个循环的意图也十分容易理解。然而对于编译器以及运行时库的组合而言,要在多个线程之间计划好这个循环,它还需要类似于OpenMP编译指示一类的指示来告诉它哪里有优化的空间:

 

  1. std::vector< int> v;  
  2. v.push_back(1);  
  3. v.push_back(5);  
  4. int total = 0;  
  5. #pragma omp for  
  6. for (int ix = 0; ix <  v.size(); ++ix){  
  7. #pragma omp atomic  
  8. total += v[ix];  

 

第一个OpenMP指示提出了多线程运行for循环的要求,而第二个omp atomic指示则被用来防止多线程同时向总数变量上写入。对于OpenMP,在MSDN库的参考文档中有关于所有指示的详细介绍。

如果使用了声明式循环技巧,那么将并行方法应用在矢量求和上则更加干净简单。STL for_each函数是一个理想的替代品,以上的例子则被改写如下:

 

  1. class Adder{  
  2. private:  
  3. int _total;  
  4. public:  
  5. Adder() : _total(0) {}  
  6. void operator ( ) ( int& i )  
  7. {  
  8. _total += i;  
  9. }  
  10. operator int ( )  
  11. {  
  12. return _total;  
  13. }  
  14. };  
  15. void VectorAdd()  
  16. {  
  17. std::vector< int> v;  
  18. v.push_back(1);  
  19. v.push_back(5);  
  20. int total = std::for_each(v.begin(), v.end(), Adder());  

这里,具体的for循环被舍弃,求矢量和的代码变得干净了一些;但是由于需要使用一系列运行符来定义一个类,这使得这个解决方案被大大的复杂化了。 除非代码库中还有大量类似的求和声明,否则一个开发者是不会仅仅为了STL for_each的那点好处而多花费功夫去定义一个新类的。

仔细检查这个Adder类,可以很明显的看出其大部分内容都仅仅是用来满足将实例用作函数对象的调用条件的。这个类中唯一起到计算作用的仅仅是那一 行_total += i。考虑到这一点,C++ 0x提供了一个被大大简化了的、以lambda函数方式来实现的语法技巧。C++ lambda函数移除了对这些搭架子代码的需求,并允许在另外的一个声明中定义 一个谓词函数。由此,VectorAdd函数可以被改写如下:

  1. std::vector< int> v;  
  2. v.push_back(1);  
  3. v.push_back(5);  
  4. int total = 0;  
  5. std::for_each(v.begin(), v.end(),  
  6. [&total](int x) {total += x;}  
  7. ); 

 

Lambda函数的语法相当直截了当。方括号中的第一个lambda元素告诉编译器,本地变量total通过引用被捕捉(这样的情况下最好用引用捕 捉,因为你需要矢量和的结果在for_each之后仍然有效),而lambda的第二部分则是参数列表。Lambda的最后一部分是函数的主体,这个例子 中就是将参数x的值加到变量total中去。

如果在C++ lambda函数中没有需要捕捉的变量,或者只需要捕捉变量的一个副本,那么函数开始的方括号可以留空:

 

  1. std::for_each(v.begin(), v.end(), [](int x) {  
  2. std::cout < <  x < <  std::endl;  
  3. }); 

混合的捕捉方法也可以使用:

 

  1. int total = 0;  
  2. bool displayInput = true;  
  3. std::for_each(v.begin(), v.end(), [&total, displayInput](int x) {  
  4. total += x;  
  5. if (displayInput){  
  6. std::cout < <  x < <  std::endl;  
  7. }  
  8. }); 

 

这里,变量displayInput通过副本被捕捉。Visual C++编译器在编译时会报错C3491:'displayInput':一个在lambda函数内数值被改变的变量无法在一个非可变lambda中通过数值被捕捉。

Lambda函数中还有一个值得注意的地方,就是它的返回值类型。编译器一般会尽可能的(也是被要求的)推断lambda表达式的返回值类型,不过 对于复杂的多行表达式而言,有可能会需要确切的声明返回值类型。返回值类型声明通过在lambda函数参数和函数主体之间添加-﹥运行符以及需要被声明的 返回值类型来实现:

 

  1. std::for_each(v.begin(), v.end(),   
  2. [&](int x)->void {total += x;});  

 

C++ lambda函数的出现,这令声明式编程以及使用STL运算法则变得更加简洁。Lambda函数允许在函数主体内的可执行代码字行间进行定义。在为 编译器提供强大的优化提示之外,Lambda函数所推崇的代码模式可以令人更加简单的理解哪段代码是要实现怎样的功能。Visual C++ 2010将带来在并行处理上的显著功能提升,而lambda函数将是具体实现这些提升的重要手段之一。

责任编辑:曹凯 来源: 博客园
相关推荐

2009-04-14 14:53:06

C++Lambda函数多线程

2009-12-29 14:00:02

WPF Dispatc

2023-12-14 15:05:08

volatile代码C++

2022-02-14 11:25:53

C++lambda函数

2012-07-03 10:48:43

C++Lambda

2009-11-25 17:54:47

PHP数组函数

2009-12-24 17:52:05

WPF触发器

2010-02-25 17:22:39

WCF服务行为

2009-12-04 17:31:32

PHP编码转换

2010-01-14 10:35:34

VB.NET指针

2009-12-29 14:58:31

WPF优点

2020-10-16 06:40:25

C++匿名函数

2011-08-22 17:13:00

LuaC++函数

2023-10-30 11:45:44

FridaC++函数

2010-01-08 18:02:33

VB.NET事件

2010-01-15 13:30:53

VB.NET Tool

2010-01-28 10:33:10

C++开发程序

2010-01-27 17:16:52

C++构造函数

2023-11-20 09:57:03

内联函数C++

2010-01-26 10:42:26

C++函数
点赞
收藏

51CTO技术栈公众号