在每次迭代的 for 循环中计算向量大小是否昂贵? [重复]

问题描述 投票:0回答:6

C++ 编译器是否处理诸如建筑物是向量之类的情况:

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

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

int n = buildings.size();
for (int i = 0; i < n; i++) {}
c++ c++11
6个回答
12
投票

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


8
投票

不要通过考虑性能来决定选择其中之一;您的编译器可能会或可能不会内联调用 - 并且

std::vector::size()
也具有恒定的复杂性。

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

如果在循环中不以任何方式修改向量,请坚持使用以前的版本以避免出现一点状态(

n
变量)。


2
投票

如果编译器可以确定

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

以明显的方式编写代码(

size
在循环内),并且只有当分析显示代码太慢时,您才应该考虑替代机制。


2
投票

我这样写循环:

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

同时处理许多问题:建议预先修复 max,不再考虑性能损失,合并类型。如果计算位于中间表达式中,则表明循环更改了集合大小。

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

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


1
投票

假设

size()
函数是基本模板的内联函数,我们也可以假设它的开销非常小。它与 C 语言中的
strlen()
有很大不同,后者可能会产生很大的开销。

使用

int n = buildings.size();
可能仍然更快 - 因为编译器可以看到
n
在循环内没有改变,因此将其加载到寄存器中,而不是间接获取向量大小。但这是非常边缘的,只有真正紧密的、高度优化的循环才需要这种处理(并且只有在分析并发现这是一个好处之后),因为在这方面事情并不总是像您期望的那样工作。


0
投票

只有在确实是性能问题时才开始手动优化此类内容。然后测量差异。否则,您将产生大量难以维护的丑陋代码,这些代码更难以调试并且使用效率较低。如果循环内的大小没有改变,大多数领先的编译器可能会优化它。

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

© www.soinside.com 2019 - 2024. All rights reserved.