2017-08-04 49 views
1

我每次回路通过一类,这是我通过指针访问一个数组里面,我问自己,这同一个问题:性能:指针引用在C++

是否每个迭代由指针的解引用开销产生?解除引用链加起来吗? 例如:

ClassA *a = new ClassA(); 
ClassB *b = new ClassB(); 

for(int i = 0; i < 10; i++){ 

    a->b->array[i].foo(); 

} 

如果我猜的话,我会说这涉及20提领步,每一个三分球,10次迭代。 但我可以想象,它减少到10,因为链接的指针被编译器翻译为单个指针。我甚至可以想象,由于一些缓存 - 巫术或其他东西,它减少到1。

有人可以告诉,也许向我解释,这是如何表现明智?会真的很感激它!

顺便说一句,我知道这种类似的问题已经在这里得到解答,但我无法推断出这个特定主题的答案。所以请不要责怪我再次提出这个话题。

+0

是B的一员吗? ClassB的全局作用域b实例与未知对象b(它是A的成员)有什么关系? – franji1

+0

“*如果我不得不猜测,我会说这涉及20个解除引导步骤*” - 30,实际上。 ''a->','b->'和'array [i]'都是指针解引用,所以每循环迭代有3次解引用,10次迭代。 –

回答

3

这真的取决于编译器(特别是优化器)如何生成代码。在as-if rule下,只要用户无法区分程序在外部的行为差异,编译器就可以做任何想做的事情,现代编译器可以非常聪明地应用它们的优化。

实际上,我认为最现代的优化器只有在无法知道foo()内发生了什么时才能优化循环 - 特别是,如果它们不能保证foo()的实现将不会更改ab的值,那么他们将被迫生成代码,对每个循环迭代执行单独的取消引用ab,只是为了确保即使ab的值发生了正确的事情更改。

你可以自己找到如果你不介意阅读一些汇编代码会发生什么 - 只需编译程序进行汇编,启用优化(例如g++ -O3 -S mytest.cpp)并读取得到的mytest.S文件以查看编译器做了什么。尝试使用在同一文件中实现的foo()(以便编译器可以明确地看到foo()的内容),并将foo实现在不同的文件中(以便编译器可能必须将foo()视为“黑色盒子“),看看有什么不同。

+0

非常感谢,我甚至没有考虑到foo()可能会改变其中一个指针的事实,但是当猜测编译器会做什么时,这实际上是一个非常有趣的事情。我不得不承认,我以前从来没有阅读过单行程序集,但我想如果我对优化感兴趣,现在是开始的好时机:D – user3808217

2

您可一定要通过做这样的事情摆脱一些反引用:

// create a pointer to the b class outside of the loop 
ClassB * bptr = a->b;   

// use the pointer inside the loop 
for(int i = 0; i < 10; i++){ 

    bptr->array[i].foo(); 

} 
+0

并且在输入之前保存一个指向'array'的指针循环,并使循环增量指针在每次迭代,而不是使用索引运算符。曾经的30个解除引用减少到10个,而不像你的例子那样是20个。 –

1

我希望1次内存访问,因为和A-> B不循环内改变,因此没有必要再次获取它们。我也知道所有的值为a-> b-> array [i],所以它可以被预取。