C++ 如果我使用lambda而不是if块,是否存在性能惩罚?
我正在使用OpenGL程序以即时模式绘制UI 要创建选项卡,请执行以下操作: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选项卡(
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:我的示例使用转发引用,它也不会复制。正确!我也可以用这个