16

c++ 编译器是否处理诸如建筑物是矢量的情况:

for (int i = 0; i < buildings.size(); i++) {}

也就是说,它是否注意到建筑物是否在循环中被修改,然后基于此不评估它每次迭代?或者也许我应该自己做这个,不是那么漂亮,但是:

int n = buildings.size();
for (int i = 0; i < n; i++) {}
4

6 回答 6

12

buildings.size()可能会被编译器内联以直接访问vector<T>类上的私有大小字段。所以你不应该把对size. 这种微优化是您无论如何都不想担心的(除非您处于某个通过分析确定为瓶颈的非常紧密的循环中)。

于 2013-06-05T16:38:13.807 回答
8

不要从性能的角度来决定是选择一个还是另一个;您的编译器可能会或可能不会内联调用 - 并且std::vector::size()也具有恒定的复杂性。

您真正应该考虑的是正确性,因为如果您在迭代时添加或删除元素,这两个版本的行为会非常不同。

如果您不在循环中以任何方式修改向量,请坚持使用前一个版本以避免一点点状态(n变量)。

于 2013-06-05T16:38:25.153 回答
2

如果编译器可以确定buildings循环内没有发生变异(例如,如果它是一个简单的循环,没有可能产生副作用的函数调用),它可能会优化计算。但是计算向量的大小无论如何都是一个减法,它也应该很便宜。

以明显的方式(在循环内)编写代码,size并且只有在分析显示它太慢时才应该考虑替代机制。

于 2013-06-05T16:41:30.307 回答
2

我写这样的循环:

for (int i = 0, maxI = buildings.size(); i < maxI; ++i)

一次处理许多问题:建议预先固定 max,不再考虑性能损失,合并类型。如果评估在中间表达式中,则表明循环更改了集合大小。

太糟糕的语言不允许合理使用 const,否则它将是 const maxI。

OTOH 对于越来越多的情况,我宁愿使用一些算法,lambda 甚至允许让它看起来几乎像传统代码。

于 2013-06-05T16:45:43.993 回答
1

假设该size()函数是基本模板的内联函数,也可以假设它的开销很小。它与strlen()可能有很大开销的 C 语言有很大不同。

使用它可能仍然更快int n = buildings.size();- 因为编译器可以看到n循环内部没有改变,所以将它加载到寄存器中而不是间接获取向量大小。但它非常微不足道,只有非常紧凑、高度优化的循环才需要这种处理(并且只有在分析并发现它是一种好处之后),因为在这种情况下,事情并不总是像你期望的那样工作。

于 2013-06-05T16:41:26.887 回答
0

如果它真的是一个性能问题,那么只有开始手动优化这样的东西。然后测量差异。否则,您将有很多难以维护的丑陋代码,这些代码更难调试,使用效率也更低。如果大小在循环内没有改变,大多数领先的编译器可能会优化它。

但即使它没有被优化掉,它也可能会被内联(因为模板默认是内联的)并且几乎没有成本。

于 2013-06-05T16:40:07.503 回答