C++ 从紧密的内部循环调用微小函数的开销?[C+;+;]

C++ 从紧密的内部循环调用微小函数的开销?[C+;+;],c++,performance,optimization,micro-optimization,C++,Performance,Optimization,Micro Optimization,假设您看到这样一个循环: for(int i=0; i<thing.getParent().getObjectModel().getElements(SOME_TYPE).count(); ++i) { thing.getData().insert( thing.GetData().Count(), thing.getParent().getObjectModel().getElements(SOME_TYPE)[i].getName() );

假设您看到这样一个循环:

for(int i=0;
    i<thing.getParent().getObjectModel().getElements(SOME_TYPE).count();
    ++i)
{
  thing.getData().insert(
    thing.GetData().Count(),
    thing.getParent().getObjectModel().getElements(SOME_TYPE)[i].getName()
    );
}
for(int i=0;

如果循环如此关键,我只能建议您查看生成的代码。如果允许编译器积极优化调用,那么这可能不会成为问题。很抱歉,现代编译器可以非常好地优化,我真的建议您通过分析来找到特定领域的最佳解决方案案例。

回答此类问题的一般方法是查看生成的程序集。对于gcc,这涉及将
-c
标记替换为
-S

我自己的规则是不反对编译器。如果要内联某些内容,那么我会确保编译器拥有执行这种内联操作所需的所有信息,并且(可能)我会尝试使用显式的
inline
关键字敦促他这样做


此外,内联可以节省一些操作码,但会使代码增长,就一级缓存而言,这可能对性能非常不利。

您提出的所有问题都是特定于编译器的,因此唯一明智的答案是“这取决于”。如果这对您很重要,您应该(一如既往地)这样做查看编译器发出的代码并进行一些计时实验。确保在编译代码时启用了所有优化功能-这可能会对
操作符[]()
等功能产生很大影响,这些功能通常作为内联函数实现,但不会内联(至少在GCC中)除非您启用优化功能。

如果方法很小,并且可以并且将被内联,那么编译器可能会执行与您相同的优化。因此,请查看生成的代码并进行比较


编辑:将常量方法标记为
const
,也很重要,例如在您的示例中
count()
getName()
应该是
const
,让编译器知道这些方法不会改变给定对象的内容。

我认为在这种情况下,您要求编译器做的事情超出了它可以访问的编译时信息的合法范围。因此,在特定情况下,凌乱的条件可能会被优化掉,但实际上,编译器并没有特别好的方法来知道长串函数调用可能会产生什么样的副作用。我假设,除非我有相反的基准测试(或反汇编),否则进行测试会更快

这是JIT编译器比C++编译器有很大优势的一个例子。它可以在运行时看到的最常见的情况下优化,并提供优化的字节码(加上检查以确保进入该情况)。.在多态方法调用中,这种方法一直被使用,但实际上并没有被多态使用;不过,我不确定它是否能捕获像您的示例那样复杂的内容


不管它值多少钱,如果速度真的很重要,我也会用Java将其拆分。

作为一项规则,您不应该在“For条件”中包含所有垃圾,除非在循环执行期间结果会发生变化


在循环外使用另一个变量集。这将在读取代码时消除WTF,不会对性能产生负面影响,并且会回避函数优化程度的问题。如果这些调用未优化,这也会导致性能提高。

有关const的说明不正确。const不作任何说明这是可以保证的。常量可能包含可变项,也可能是“丢弃的”。@Suma:是的,但至少这是对编译器的一个提示。在实践中,编译器可能会忽略常量以进行优化。我认为事实上,这是一种代码气味(“消息链”)无论如何,做点什么是有意义的。说这是一个“一般性问题”这并没有改变这样一个事实,即这是又一次尝试在没有分析的情况下进行优化。换句话说,这是一次徒劳的猜测。对不起,你错了。如果你知道你在做什么,你应该能够告诉我,不管花了多少时间,这段代码是否可以合理地进行优化。编译器可能会从循环中提取不变量为你,但那只是(也许)有助于提高性能。第二个示例更易于阅读,因为您为长表达式指定了有意义的名称。编译器永远不会使代码更具可读性。++我的观点完全正确。我甚至在知道这实际上是性能问题之前就倾向于这样做。顺便说一句,您的自我描述听起来非常有趣。多态内联cach任何自尊心的JIT都会很容易地优化这个例子。虽然静态C++编译器可以在整个程序优化和配置文件反馈的情况下进行PICS,但我并不知道任何编译器都能做到这一点。
ElementContainer &source = 
   thing.getParent().getObjectModel().getElements(SOME_TYPE);
int num = source.count();
Store &destination = thing.getData();
for(int i=0;i<num;++i)
{
  destination.insert(thing.GetData().Count(), source[i].getName());
}