是否应评估或存储循环限制?

Pro*_*mer 17 c++ optimization

在C++中,将变量的限制存储在变量中比评估值更快吗?

例如:

这是一种较慢的使用方法

for(int i=0; i<n*n+2*n; ++i)
{ .... }
Run Code Online (Sandbox Code Playgroud)

而不是做以下?

for(int i=0, limit=n*n+2*n; i<limit; ++i)
{ .... }
Run Code Online (Sandbox Code Playgroud)

为清楚起见,假设n某个给定变量在循环过程中保持不变.

Bat*_*eba 21

如果n是全局声明的非volatile变量,那么行为

for (int i = 0; i < n * n + 2 * n; ++i)

不确定.n * n + 2 * n即使另一个线程修改,也允许编译器进行优化以进行一次评估n.此外,如果另一个线程能够修改n,那么您应该采取措施避免同时读取和写入的可能性n(其行为未定义).考虑使用std::atomic<int>作为类型n.

limit无论如何,如果您希望在n程序控制到达for循环时停止条件依赖于observable 的值,那么无论出于何种性能考虑,都应该引入.因此,请考虑

for (int i = 0, limit = n * n + 2 * n; i < limit; ++i)

其优点是limit不会泄漏到周围的陈述范围内.

但是如果你能够,你总是可以向后运行循环:

for (int i = n * n + 2 * n - 1; i >= 0; --i)

非常小心,虽然与unsigned类型,如果你采用这种想法.

  • "行为未指定"并未遵循"允许编译器优化...即使另一个线程修改`n`".如果没有其他线程修改`n`,则行为定义良好.如果另一个线程确实修改了`n`,那么行为是未定义的,并且引入`limit`并不能解决这个问题. (13认同)

Vio*_*ffe 7

在热点之外没关系.我的意思是 - 是的,在没有编译器优化的情况下,在调试中只计算一次值会更快,并且至少在发布时速度快.但它通常无关紧要.这样做更容易编写,阅读和维护.让我引用唐纳德克努特的名言:

真正的问题是程序员花费了太多时间来担心在错误的地方和错误的时间提高效率; 过早优化是编程中所有邪恶(或至少大部分)的根源.

话虽如此,我最近喜欢这种方式:

for (int i = 0, upperBound = n*n + 2*n /*or n*(n + 2)*/; i < upperBound; ++i)
{
}
Run Code Online (Sandbox Code Playgroud)

这样,范围upperBound仅限于for语句本身,并且不会渗透到不需要它的外部范围.

  • @Walter:任何微观优化都是不必要的.这种问题实际上就是Knuth所说的. (8认同)
  • 目前还不清楚Knuths的报价在这里如何重要.为什么这种微观优化是邪恶的? (3认同)
  • 将D. Knuth的引用放入其原始上下文时,可以解决一些讨论,如他的文章中所述*使用goto语句进行结构化编程*:*"我们应该忘记小的效率,比如大约97%的时间:过早的优化是所有邪恶的根源.**然而,我们不应该在那个关键的3%**中放弃我们的机会.一个优秀的程序员不会因为这样的推理而变得自满,他会明智地仔细研究关键代码;但只有在识别出代码之后."*(由我强调.也许我们在这里讨论这些3%......) (3认同)