性能:指针在C++中取消引用

Performance: Pointer dereferencing in C++

本文关键字:取消 引用 C++ 指针 性能      更新时间:2023-10-16

每次我遍历类中的数组(通过指针访问该数组(时,我都会问自己同样的问题:

每次迭代是否通过取消引用指针产生开销?取消引用链加起来吗? 例如:

ClassA *a = new ClassA();
ClassB *b = new ClassB();
for( int i = 0; i < 10; i++){
a->b->array[i].foo();
}

如果我不得不猜测,我会说这涉及 20 个取消引用步骤,每个指针一个,10 次迭代。 但我也可以想象,它减少到 10 个,因为链接指针由编译器转换为单个指针。我什至可以想象,由于一些缓存伏都教或其他东西,它被减少到 1。

有人可以告诉,也许向我解释一下,这在性能方面是如何表现的吗?真的很感激!

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

这实际上取决于编译器(尤其是优化器(想要如何生成代码。 在 as-if 规则下,只要用户无法分辨出程序外部行为的差异,编译器就可以做任何它想做的事情,现代编译器就可以在他们应用的优化方面变得非常聪明。

在实践中,我认为最现代的优化器只有在无法判断 foo(( 内部发生了什么时才无法优化循环——特别是,如果他们不能保证 foo(( 的实现不会改变ab的值,那么他们将被迫生成代码,为每个循环迭代执行单独的ab取消引用, 只是为了确保即使ab的价值观发生变化,也会发生正确的事情。

如果您不介意阅读一些汇编代码,您可以自己找出会发生什么 - 只需将程序编译为汇编,并启用优化(例如g++ -O3 -S mytest.cpp(,并读取生成的 mytest。S 文件以查看编译器执行的操作。 尝试使用在同一文件中实现的 foo(((这样编译器肯定可以看到 foo(( 的内容(和在不同的文件中实现的 foo(这样编译器可能不得不将 foo(( 视为"黑匣子"(,看看这有什么区别。

你可以确保通过做这样的事情来摆脱一些取消引用:

// 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();
}

我希望有1 次内存访问,因为 a 和 a->b 在循环中不会改变,所以没有必要再次获取它们。此外,i的所有值对于a->b->array[i]都是已知的,因此可以预取。