C ++ 11 lambda表达式背后的动机是什么?

时间:2010-06-10 21:21:38

标签: c++ lambda c++11

我试图找出在C ++中使用lambda表达式是否存在实际的计算好处,即“此代码编译/运行更快/更慢因为我们使用lambda表达式”< / em>或者它只是一个整洁的开发特权,可供那些试图看起来很酷的可怜的程序员滥用?

我理解这个问题可能看似主观,但我非常感谢社群对此事的看法。

8 个答案:

答案 0 :(得分:43)

好处是编写计算机程序最重要的好处: 更容易理解代码 。我不知道任何性能方面的考虑。

C ++允许在某种程度上进行功能编程。考虑一下:

std::for_each( begin, end, doer );

这个问题是函数(对象)doer

  1. 指定在循环中完成
  2. 还有点隐藏了实际完成的内容(你必须查找函数对象的operator()的实现)
  3. 必须在与std::for_each调用
  4. 不同的范围中定义
  5. 包含一定数量的样板代码
  6. 通常是丢弃代码除了这个循环结构之外什么都不用。
  7. Lambdas在所有这些方面都有了很大改进(也许还有一些我忘了)。

答案 1 :(得分:41)

我认为计算性能几乎与提高语言的表达能力差不多。

答案 2 :(得分:13)

本身没有性能优势,但由于STL及其设计理念的广泛采用,对lambda的需求也随之而来。

具体来说,STL算法经常使用仿函数。如果没有lambda,则需要先声明这些函子被使用。 Lambdas可以拥有“匿名”的就地仿函数。

这很重要,因为在很多情况下你只需要使用一个仿函数,并且你不想为它命名,原因有两个:你不想污染名称空间,并且在这些特定情况下,您提供的名称要么模糊,要么非常长。

例如,我使用STL很多,但没有C ++ 0x我使用的for()循环比for_each()算法及其表兄弟多得多。那是因为如果我使用for_each()代替,我需要从循环内部获取代码并为它声明一个仿函数。此外,循环之前的所有局部变量都不可访问,因此我需要编写其他代码以将它们作为参数传递给仿函数构造函数,或者其他等价物。因此,除非有强烈的动机,否则我倾向于不使用for_each(),否则代码会更长,更难以阅读。

这很糟糕,因为众所周知,使用for_each()和类似的算法为编译器提供了更多的空间。用于优化的库,包括自动并行。因此,间接地,lambda将支持更高效的代码。

答案 3 :(得分:9)

IMO,关于lambda的最重要的事情是它将相关代码保持在一起。如果你有这个代码:

std::for_each(begin, end, unknown_function);

您需要导航到unknown_function以了解代码的作用。但是使用lambda,逻辑可以保持在一起。

答案 4 :(得分:8)

Lambdas是函子类的语法糖,所以不,没有计算上的好处。至于动机,可能是其他十几种流行语言中的任何一种都有lambdas吗?

有人可能会说它有助于代码的可读性(让你的函子在内联函数中声明它被使用)。

答案 5 :(得分:5)

虽然我认为C ++ 0x的其他部分是more important,但lambdas不仅仅是C ++ 98样式函数对象的“语法糖”,因为它们可以捕获上下文,并且它们会这样做按名称,然后他们可以将这些上下文带到其他地方并执行。这是新的东西,而不是“编译更快/更慢”的东西。

#include <iostream>
#include <vector>
#include <functional>
void something_else(std::function<void()> f)
{
        f(); // A closure! I wonder if we can write in CPS now...
}
int main()
{
        std::vector<int> v(10,0);
        std::function<void ()> f = [&](){ std::cout << v.size() << std::endl; };

        something_else(f);
}

答案 6 :(得分:2)

好吧,比较一下:

int main () {
    std::vector<int> x = {2, 3, 5, 7, 11, 13, 17, 19};

    int center = 10;
    std::sort(x.begin(), x.end(), [=](int x, int y) {
        return abs(x - center) < abs(y - center);
    });

    std::for_each(x.begin(), x.end(), [](int v) {
        printf("%d\n", v);
    });

    return 0;
}

用这个:

// why enforce this to be defined nonlocally?
void printer(int v) {
    printf("%d\n", v);
} 

int main () {
    std::vector<int> x = {2, 3, 5, 7, 11, 13, 17, 19};

    // why enforce we to define a whole struct just need to maintain a state?
    struct {
        int center; 
        bool operator()(int x, int y) const {
            return abs(x - center) < abs(y - center);
        }
    } comp = {10};

    std::sort(x.begin(), x.end(), comp);

    std::for_each(x.begin(), x.end(), printer);

    return 0;
}

答案 7 :(得分:2)

一个整洁的开发特权,让那些试图看起来很酷的可怜的程序员滥用?”......无论你怎么称呼它,它都会让代码变得更强大更具可读性维护。它不会提高性能。

大多数情况下,程序员会迭代一系列元素(搜索元素,累积元素,排序元素等)。使用函数式,您可以立即看到程序员打算做什么,与使用for循环不同,其中所有内容都“看起来”相同。

比较算法+ lambda:

iterator longest_tree = std::max_element(forest.begin(), forest.end(), [height]{arg0.height>arg1.height});
iterator first_leaf_tree = std::find_if(forest.begin(), forest.end(), []{is_leaf(arg0)});
std::transform(forest.begin(), forest.end(), firewood.begin(), []{arg0.trans(...));
std::for_each(forest.begin(), forest.end(), {arg0.make_plywood()});

使用oldschool for-loops;

Forest::iterator longest_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
   if (*it.height() > *longest_tree.height()) {
     longest_tree = it;
   }
}

Forest::iterator leaf_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
   if (it->type() == LEAF_TREE) {
     leaf_tree  = it;
     break;
   }
}

for (Forest::const_iterator it = forest.begin(), jt = firewood.begin(); 
     it != forest.end(); 
     it++, jt++) {
          *jt = boost::transformtowood(*it);
    }

for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
    std::makeplywood(*it);
}

(我知道这段代码包含语法错误。)