使用C++的范围循环比递减循环更快。

3
我们经常以这种方式从最后一个元素开始循环遍历数组:

static const char* pszStrings[] = { ... }
for (size_t i = _countof(pszStrings); i--;)
    use(pszStrings[i]);

我的问题是,如果新的基于范围的for循环同样高效并且可以使用:

static const char* pszStrings[] = { ... }
for (auto string : pszStrings)
    use(string);

此外...

由于我无法查看生成的代码,即使能够查看,我也不知道是否能够得出正确的结论,因此我希望您能提供不太科学的答案!


4
范围-based 循环将迭代另一个方向,因此您正在比较两个执行不同操作的循环。 - interjay
3
通常我们会倒序遍历数组,我觉得这很令人沮丧,你真的需要这种微小的优化来换取比可读代码更多的性能吗? - Drax
1
是的@interjay,我比较了两个不同的循环。如果方向不重要,我们使用带有空迭代器块的“反向”循环。 - Martin Lemburg
1
是的@Drax,我们需要在我们的系统中进行微观优化。这是因为生产模拟系统可能用于非常庞大的场景,其中每个确保的内存对齐、防止内存碎片化、每个节省的CPU周期都可能对模拟速度和运行时间产生积极影响! - Martin Lemburg
1个回答

5
编译器在新的范围for循环中可以对迭代集合做出许多假设,而在先前编写的for循环中则不然。例如:
在C++98时代,通常会这样写:
for (std::vector<int>::const_iterator it = v.begin(), it_end = v.end(); 
     it != it_end; ++it) {
    // code ..
}

使用it_end的原因是在许多情况下,编译器无法确定集合在 for 循环内部是否会改变大小(.end() 可能会发生变化)。如果您编写:

for (std::vector<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
    // code ..
}

编译器可以为每次循环执行生成对 .end() 函数的调用。

range for-loop 和旧的 for-loop 一样有效率(有时更高效)。

例如:

如果您有一个使用下标迭代 std::vector 的循环: for (int i = 0; i < v.size(); ++i) ,此循环需要索引向量以使用元素(v[i])在大型 vector 上可能不会显著等待,但在紧密循环中会被注意到。

这种类型的循环通过更新为 range for-loop 可以改进。

答案中的第一个循环可能不会提高性能,但会提高代码的清晰度,代码的读者将知道代码意味着迭代整个集合而不是跳过某些元素(在旧的方式中,您可以在 for-loop 中识别出 for-each pattern,但如果不小心,它会变得繁琐且可能导致有关代码的错误结论(可能在主体中修改索引或迭代器)。


1
我们的反向循环在最后一个部分为空,因此在运行时循环结束时没有任何操作可执行。 这样可以节省一些时钟周期。希望基于范围的循环已经进行了足够的优化,以避免不必要的方法调用,比如end()。我更喜欢基于范围的循环,因为它更易读,并且编写循环体更加简单。 - Martin Lemburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接