lambda 是否像 C++ 中的函数一样内联?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15930755/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:54:43  来源:igfitidea点击:

Are lambdas inlined like functions in C++?

c++c++11lambdastl

提问by Illia Levandovskyi

Can/does the compiler inline lambda functions to increase efficiency, as it might with simple standard functions?

编译器是否可以内联 lambda 函数来提高效率,就像使用简单的标准函数一样?

e.g.

例如

std::vector<double> vd;
std::for_each(vd.begin(), vd.end(), [](const double d) {return d*d;});

Or is there loss of efficiency caused by lack of optimisation?

还是因为缺乏优化而导致效率下降?

A second question: where I can check if the compiler I use has optimised calls of inline functions, which are sent to an algorithm? What I mean is, if a function—not a function object—is sent to an algorithm, the last one gets a pointer to the function, and some compilers optimize pointers to inline functions and others don't.

第二个问题:我在哪里可以检查我使用的编译器是否优化了内联函数的调用,这些调用被发送到算法?我的意思是,如果一个函数——而不是一个函数对象——被发送到一个算法,最后一个得到一个指向该函数的指针,一些编译器优化指向内联函数的指针,而另一些则没有。

回答by Ali

In simple cases, like your example, you should expect better performance with lambdas than with function pointers,see

在简单的情况下,如您的示例,您应该期望使用 lambdas 比使用函数指针具有更好的性能,请参阅

Why can lambdas be better optimized by the compiler than plain functions?

为什么编译器可以比普通函数更好地优化 lambdas?

As others have already pointed out, there is no guarantee that your call will be inlined but you have better chances with lambdas. One way of checking whether the call has been inlined is to check the generated code. If you are using gcc, pass the -S flag to the compiler. Of course, it assumes that you can understand the assembly code.

正如其他人已经指出的那样,不能保证您的调用会被内联,但您有更好的机会使用 lambda。检查调用是否已内联的一种方法是检查生成的代码。如果您使用 gcc,请将 -S 标志传递给编译器。当然,它假设您可以理解汇编代码。





Update on Sep 11, 2018:Vipul Kumarpointed out two compiler flags in his edit.

2018 年 9 月 11 日更新:Vipul Kumar在他的编辑中指出了两个编译器标志。

GCC -Winline

海湾合作委员会 -Winline

Warn if a function that is declared as inline cannot be inlined. Even with this option, the compiler does not warn about failures to inline functions declared in system headers.

The compiler uses a variety of heuristics to determine whether or not to inline a function. For example, the compiler takes into account the size of the function being inlined and the amount of inlining that has already been done in the current function. Therefore, seemingly insignificant changes in the source program can cause the warnings produced by -Winline to appear or disappear.

如果不能内联声明为 inline 的函数,则发出警告。即使使用此选项,编译器也不会警告系统头文件中声明的内联函数失败。

编译器使用各种启发式方法来确定是否内联函数。例如,编译器会考虑被内联的函数的大小以及当前函数中已经完成的内联量。因此,源程序中看似微不足道的更改可能会导致 -Winline 产生的警告出现或消失。

As I understand this, if your function is not declared inline, this compiler flag is most likely nothelpful. Nevertheless it is good to know it exists and it partly answers your second question.

据我了解,如果您的函数未声明为内联,则此编译器标志很可能没有帮助。尽管如此,知道它存在还是很好的,它部分回答了你的第二个问题。

The other flag that he pointed out is:

他指出的另一个标志是:

Clang -Rpass=inline

-Rpass=inline

Options to Emit Optimization Reports

Optimization reports trace, at a high-level, all the major decisions done by compiler transformations. For instance, when the inliner decides to inline function foo() into bar() [...]

发出优化报告的选项

优化报告在高层次上跟踪由编译器转换完成的所有主要决策。例如,当内联程序决定将函数 foo() 内联到 bar() [...]

I haven't used this one myself but based on the documentation it might be useful for your use case.

我自己没有使用过这个,但根据文档,它可能对您的用例有用。

I personally check the generated assembly whenever it is that important.

每当生成的程序集很重要时,我都会亲自检查它。

回答by Konrad Rudolph

First off: the whole point of the design of lambdas in C++ is that they don't have an overhead compared to function calls. That notably includes the fact that calls to them can be inlined.

首先:在 C++ 中设计 lambda 的全部意义在于,与函数调用相比,它们没有开销。这尤其包括对它们的调用可以内联的事实。

But there's a confusion of concepts here: in the C++ standard, “inline” is the linkageof a function, i.e. it is a statement about how a function is defined, not how it gets called. Functions that are defined inline canbenefit from a compiler optimisation by which calls to such functions are inlined. It's a different but highly related concepts.

但是这里有一个概念混淆:在 C++ 标准中,“内联”是函数的链接,即它是关于函数如何定义的声明,而不是它如何被调用。内联定义的函数可以受益于编译器优化,通过该优化可以内联对此类函数的调用。这是一个不同但高度相关的概念。

In the case of lambdas, the actual function being called is a member operator()that is implicitly defined as inlinein an anonymous class created by the compiler for the lambda. Calls of the lambda are translated to direct calls to its operator()and can therefore be inlined. I've explained how the compiler creates lambda types in more detail in another answer.

在 lambda 的情况下,被调用的实际函数operator()是隐式定义inline为由编译器为 lambda 创建的匿名类中的成员。对 lambda 的调用被转换为对其的直接调用,operator()因此可以被内联。我已经在另一个答案中更详细地解释了编译器如何创建 lambda 类型

回答by pconnell

It depends on the optimisation level given to the compiler. Take for example, these two functions, which are semantically identical. One is C++11 style, the other C style.

这取决于提供给编译器的优化级别。以这两个函数为例,它们在语义上是相同的。一种是 C++11 风格,另一种是 C 风格。

void foo1 (void)
{
    int arr[100];
    std::generate(std::begin(arr), std::end(arr), [](){return std::rand()%100;});
}

void foo2 (void)
{
    int arr[100];
    for (int *i = arr; i < arr+100; i++) *i = std::rand()%100;
}

Compiling this with gcc -O4 emits code which is extremely similar (not identical, but equivalent complexity) for the two functions.

使用 gcc -O4 编译它会发出两个函数非常相似的代码(不完全相同,但复杂度相当)。

However the lambda is not inlined when compiling unoptimised (and neither are the std::begin and std::end calls).

然而,当编译未优化时,lambda 不会内联(std::begin 和 std::end 调用也不是)。

So although the compiler can (and does) do an excellent job at optimizing the modern style code when asked to do so, there is possibly or probably going to be a performance penalty for this kind of code in an unoptimized debug build.

因此,尽管编译器可以(并且确实)在被要求优化现代风格代码方面做得非常出色,但在未优化的调试版本中,此类代码可能会或可能会受到性能损失。