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



假设:

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这样的现代编译器足够聪明,可以在内部将索引表单转换为指针形式。

但是,看到您使用的是MS Visual Studio,您最好坚持使用索引形式,因为它更适合MS Visual Studio的矢量化优化器。

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

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

差异将过于混乱,无法制定一般规则。

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

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

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

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

第二个的优点是你模仿了迭代器语法C++"现代"。 (但是,我很想使用!=而不是<,因为比较结构的末尾过去的指针是未定义的行为,因此您应该确保在末尾停止,而不是吹过它)。

你的问题的真正问题是,它几乎肯定是过早的优化。 如果不是过早优化,则应确定此代码是性能瓶颈,并且应进行分析并确定哪个更快,而不是寻找经验法则。

在"编写不过早悲观的代码"的层面上,两者都不是真正的赢家。 清晰度的重要性胜过您将遇到的任何性能差异。 清晰度对性能很重要,因为清晰、易于理解的代码更容易优化,而定向优化(您解决性能瓶颈并使其性能更好)比阅读由不必要的微优化引起的不明确代码更好地利用性能改进时间。

最新更新