用指针替换循环索引器有什么好处吗?

Is there any benefit to replacing loop indexers with pointers?

假设:

const int n = bigNumber;
float* f = someData;

转换有什么意义

for (int i = 0; i < n; i++)
{
    f[i] += 1;
}

float* lastF = f + n;
for (float* i = f; i < lastF; i++)
{
    *i += 1;
}

天真地看着这个,似乎我为每次迭代(f[i])保存了一个加法运算。

当然,这是假设我对循环内索引器的值不感兴趣。

  1. 我的这种心态是否正确?
  2. 如果是这样,我的编译器是否足够聪明,可以自行执行此操作(假设启用了所有优化标志)?

我会检查反汇编,但我不擅长阅读那些。

没有任何好处。现在任何编译器都可以比大多数程序员做得更好更快。

如果 f[i++] 在您的代码中比 *fp++ 更具可读性,请不要三思。它们将被编译为完全相同的目标代码。

像 MS Visual Studio 这样的现代编译器足够聪明,可以在内部将索引形式转换为指针形式。

但是,看你用的是MSVisual Studio,你最好坚持索引形式,因为它更适合MSVisual Studio的vectorizing optimizer

索引形式是推荐的形式,Visual Studio更容易理解。编译器更难理解指针形式;如果编译器感到困惑,您可能无法理解原因。

例如,在我的 Visual Studio 编译器(2013 版)中,索引形式被编译成 AVX 代码(256 位寄存器,如 ymm0),而指针形式使用 SSE(128-位寄存器,如 xmm0) - 可能工作速度慢 2 倍(未测量)。

差异会很混乱,没有一个通用的规则。

这两段代码在逻辑上是等价的,因此在 as-if 下,编译器可以自由地将其中一个视为另一个。

如果 i 的值或地址被采用,情况会发生变化,特别是如果它被传递 "non locally",因为这会迫使编译器放弃将一个转换为另一个的能力。

一些编译器可能会被其中一个混淆,但不会被另一个混淆。

第一个的优点是迭代索引元素。

第二个的优点是您正在模仿 "modern" C++ 迭代器语法。 (然而,我很想使用 != 而不是 <,因为比较指针超过结构的最后一个是未定义的行为,所以你应该确定在结束,不要吹过去)。

你的问题的真正问题在于它几乎可以肯定是过早的优化。如果不是过早的优化,您应该确定这段代码是性能瓶颈,您应该分析并确定哪个更快,而不是寻找经验法则。

在 "writing code that isn't prematurely pessimized" 的水平上,两者都没有真正获胜。清晰度的重要性胜过您将体验到的任何性能差异。清晰度对性能很重要,因为清晰、易于理解的代码更容易优化,而定向优化(您解决性能瓶颈并使其性能更好)比阅读因不需要而导致的不清晰代码更好地利用性能改进时间微优化。