c++ 编译器是否处理诸如建筑物是矢量的情况:
for (int i = 0; i < buildings.size(); i++) {}
也就是说,它是否注意到建筑物是否在循环中被修改,然后基于此不评估它每次迭代?或者也许我应该自己做这个,不是那么漂亮,但是:
int n = buildings.size();
for (int i = 0; i < n; i++) {}
buildings.size()
可能会被编译器内联以直接访问vector<T>
类上的私有大小字段。所以你不应该把对size
. 这种微优化是您无论如何都不想担心的(除非您处于某个通过分析确定为瓶颈的非常紧密的循环中)。
不要从性能的角度来决定是选择一个还是另一个;您的编译器可能会或可能不会内联调用 - 并且std::vector::size()
也具有恒定的复杂性。
您真正应该考虑的是正确性,因为如果您在迭代时添加或删除元素,这两个版本的行为会非常不同。
如果您不在循环中以任何方式修改向量,请坚持使用前一个版本以避免一点点状态(n
变量)。
如果编译器可以确定buildings
循环内没有发生变异(例如,如果它是一个简单的循环,没有可能产生副作用的函数调用),它可能会优化计算。但是计算向量的大小无论如何都是一个减法,它也应该很便宜。
以明显的方式(在循环内)编写代码,size
并且只有在分析显示它太慢时才应该考虑替代机制。
我写这样的循环:
for (int i = 0, maxI = buildings.size(); i < maxI; ++i)
一次处理许多问题:建议预先固定 max,不再考虑性能损失,合并类型。如果评估在中间表达式中,则表明循环更改了集合大小。
太糟糕的语言不允许合理使用 const,否则它将是 const maxI。
OTOH 对于越来越多的情况,我宁愿使用一些算法,lambda 甚至允许让它看起来几乎像传统代码。
假设该size()
函数是基本模板的内联函数,也可以假设它的开销很小。它与strlen()
可能有很大开销的 C 语言有很大不同。
使用它可能仍然更快int n = buildings.size();
- 因为编译器可以看到n
循环内部没有改变,所以将它加载到寄存器中而不是间接获取向量大小。但它非常微不足道,只有非常紧凑、高度优化的循环才需要这种处理(并且只有在分析并发现它是一种好处之后),因为在这种情况下,事情并不总是像你期望的那样工作。
如果它真的是一个性能问题,那么只有开始手动优化这样的东西。然后测量差异。否则,您将有很多难以维护的丑陋代码,这些代码更难调试,使用效率也更低。如果大小在循环内没有改变,大多数领先的编译器可能会优化它。
但即使它没有被优化掉,它也可能会被内联(因为模板默认是内联的)并且几乎没有成本。