我想知道当函数作为文章传递时,C ++是否仍然会服从inline
关键字。在以下示例中,每次onFrame
循环中调用frame()
时,是否会将while
的新帧推入堆栈?
bool interrupt = false;
void run(std::function<void()> frame) {
while(!interrupt) frame();
}
inline void onFrame() {
// do something each frame
}
int main() {
run(onFrame);
}
或者改变这个有什么影响?
void run(std::function<inline void()> frame) {
while(!interrupt) frame();
}
如果您没有明确答案,可以帮我找到测试方法吗?可能使用内存地址或某种调试器?
答案 0 :(得分:8)
如果必须通过std::function
类型删除的调度来实现,那么编译器很难内联您的函数。它无论如何都可能发生,但你要尽可能地努力。你提议的替代方案(采用std::function<inline void()>
论证)是不正确的。
如果您不需要删除类型,请不要使用类型擦除。 run()
可以简单地采用任意的可调用:
template <class F>
void run(F frame) {
while(!interrupt) frame();
}
muuch 更容易内联编译器。虽然,简单地使用inline
函数本身并不能保证函数内联。请参阅this answer。
另请注意,当您传递函数指针时,这也会降低内联的可能性,这很不方便。我试图在这里找到一个有一个很好的例子的答案,但在那之前,如果内联非常重要,将它包装成lambda可能是要走的路:
run([]{ onFrame(); });
答案 1 :(得分:3)
仍然遵守
inline
关键字......将新框架推送到堆栈
这不是inline
关键字首先执行的操作(请参阅this question以获取广泛参考)。
假设,正如Barry所做的那样,你希望说服优化器内联你的函数调用(再次为了运气:这与inline
关键字无关),函数模板+ lambda可能是要走的路。
要了解其原因,请考虑优化器在每种情况下必须使用的内容:
功能模板+ lambda
template <typename F>
void run(F frame) { while(!interrupt) frame(); }
// ... call site ...
run([]{ onFrame(); });
这里,该函数仅在调用站点存在(从模板实例化),优化器需要在范围内工作并且定义良好。
请注意,如果优化器认为额外的指令缓存压力超过堆栈帧的保存,则可能仍然合理地选择不内联调用
函数指针
void run(void (*frame)()) { while(!interrupt) frame(); }
// ... call site ...
run(onFrame);
这里,run
可能必须编译为一个独立的函数(尽管如果它可以证明没有人使用它,链接器可能会丢弃该副本),onFrame
也是如此,特别是因为它的地址。最后,在决定是否内联这些调用时,优化器可能需要考虑是否使用许多不同的函数指针调用run
,或者只调用一个函数指针。总的来说,它似乎更多的工作,并可能最终作为链接时优化。
NB。我使用“独立功能”来表示编译器可能会发出代码&amp;两种情况下正常自由函数的符号表条目。
std::function
这已经很久了。让我们注意到这个类很长( type erasure Barry提到)来实现这个功能
void run(std::function<void()> frame);
not 取决于函数的确切类型,这意味着在生成run
的代码时隐藏编译器中的信息,这意味着优化器可以使用的更少(或者相反,需要做更多工作来撤消所有细心的信息隐藏)。
至于测试你的优化器所做的事情,你需要在整个程序的上下文中检查它:它可以根据代码大小和复杂性自由选择不同的启发式方法。
要完全确定实际上做了什么,只需用源代码反汇编或编译成汇编程序。 (是的,这可能是一个很大的“公正”,但它是特定于平台的,而不是真正的问题主题,以及值得学习的技能)。
答案 2 :(得分:0)
编译发布并检查列表文件,或在调试器中打开反汇编。最好的方法是检查生成的代码。