C++ 如果我使用lambda而不是if块,是否存在性能惩罚?

C++ 如果我使用lambda而不是if块,是否存在性能惩罚?,c++,performance,c++11,lambda,C++,Performance,C++11,Lambda,我正在使用OpenGL程序以即时模式绘制UI 要创建选项卡,请执行以下操作: if(ImGui::BeginTabItem(“某些选项卡”)){ //东西 ImGui::EndTabItem(); } 我来自Kotlin,在那里您通常使用如下结构: something(“blablablabla”){x-> //随便 }//这是Kotlin lambda顺便说一句 因此,我编写了一个简单的包装器来包装调用,而不是编写if和end调用,以避免意外忽略end调用: inline void选项卡(

我正在使用OpenGL程序以即时模式绘制UI

要创建选项卡,请执行以下操作:

if(ImGui::BeginTabItem(“某些选项卡”)){
//东西
ImGui::EndTabItem();
}
我来自Kotlin,在那里您通常使用如下结构:

something(“blablablabla”){x->
//随便
}//这是Kotlin lambda顺便说一句
因此,我编写了一个简单的包装器来包装调用,而不是编写if和end调用,以避免意外忽略end调用:

inline void选项卡(常量字符*标签,std::函数fn)
{
if(ImGui::BeginTabItem(标签)){
fn();
ImGui::EndTabItem();
}
}
将第一个代码段替换为以下内容:

ui::tab(“其他一些选项卡”,[]{
//更多用户界面。。。
});
问题是,编译器会发出类似的代码吗?还是会对性能产生很大影响

我担心,如果每次绘制UI时编译器只是放置一个新的可调用结构,这将是一个问题

另外,我正在捕获
这个
指针,以便在内部使用

if(ImGui::BeginTabItem(“某些选项卡”)){
//东西
ImGui::EndTabItem();
}
//--对--//
ui::tab(“其他一些选项卡”,[this]{
//更多用户界面。。。
});
如果我使用lambda而不是if块,是否存在性能惩罚

这取决于编译器和标志

通过调用一个名为
gcc-Wall-O3-mtune=native
,您会惊讶于它能够进行的优化,包括。您甚至可能对链接时间优化和整个程序优化感兴趣(e.c.编译并链接
gcc-O3-flto-fwhole程序
…)。了解GCC

参见H2020项目资助的示例报告

当然,邪恶在于细节

您可以通过改进更多的优化来扩展GCC

但是,请注意,编译器优化在理论上是不可确定的(参见、、、项目等),实际上是不完美的(与其说是科学,不如说是一门艺术)

当前高端处理器(,)的复杂性(和商业秘密)使得分析几乎不可能。在实践中,您会遇到编译器优化会让您失望的情况。因此,将精力放在(例如,使用Linux或在Linux上)

另请参见、和项目。还要考虑,

别忘了资助和支持专门从事优化的研究团队,例如给我发电子邮件到
basile@starynkevitch.net
(但预算要求超过10万欧元,延迟时间超过一年)

最后,您可以(在许多平台上)在运行时生成特定的代码(使用技术)。然后考虑使用诸如在某些操作系统上,可以在运行时生成C++代码,然后编译它并加载它作为(例如)。 当然要读汤普森的报纸和杂志

你当然可以考虑使用或。在主要的计算平台上,两者都可以与C++混合,并且实际上有助于运行时代码生成,因此可以通过努力提高执行时间。 您正在编码:

inline void选项卡(const char*label,std::function fn)

(如果
fn
可能间接地抛出了一些异常,那么您的代码不会做您想要的事情)我建议您改为

 inline void tab(const char* label, const std::function<void()>& fn)
inline void选项卡(常量字符*标签,常量标准::函数&fn)

您似乎不需要
std::function
提供的全部功能(特别是它的运行时多态行为),因此最好不要使用它

只需使用模板函数,这对于编译器来说更容易优化:

template <typename CALLABLE>
void tab(const char* label, CALLABLE &&fn)
{
    if (ImGui::BeginTabItem(label)) {
        std::forward<CALLABLE>(fn)();
        ImGui::EndTabItem();
    }
}
模板
void选项卡(常量字符*标签,可调用(&fn)
{
if(ImGui::BeginTabItem(标签)){
标准:前进(fn)();
ImGui::EndTabItem();
}
}
如果您希望避免模板版本中的代码膨胀,并且希望将
tab
作为非内联函数,那么我在这里使用
std::function


原因是
std::function
可能是一个更糟糕的解决方案,因为
std::function
需要将lambda(及其捕获的变量)存储在某个地方。堆通常用于此目的(除非它适合
std::function
的小对象优化空间-但现在您依赖的是
std::function
的实现确实具有这个小对象空间,并且编译器能够围绕此进行优化)。因此,只使用模板版本更容易,编译器在优化这方面做得非常好,因为标准库大量使用这项技术。

我不会担心“每次绘制UI时都会出现新的可调用结构”。仅用于清理的类是一种常见模式,例如
作用域锁定
unqiue锁定
等,并且编译器非常擅长优化填充,因为它们通常不会出现性能问题<代码>标准::函数
可以。在启用所有优化的情况下,分析代码。分析是了解情况的唯一方法。如果没有评测,你只是在猜测。在什么操作系统、编译器和平台上?@BasileStarynkevitch g++9.2.0(MSYS2),Windows 10可能应该是
-mtune=native
我知道这是一个相当困难的主题,我运行了一个快速工作台(我不知道设置是否正确):所以可能它可以。我现在将使用lambdas,看看将来是否会出现问题。PS:谢谢你的资源!感谢模板提示!我已切换到模板const ref,以避免复制我传递的任何内容。@SigmaSoldier:我的示例使用转发引用,它也不会复制。正确!我也可以用这个