C++:arr.size() 是循环的良好条件吗?

C++: Is arr.size() a good condition for a loop?

本文关键字:条件 循环 arr size C++      更新时间:2023-10-16

如果有一个名为arr的向量包含大量数据,我将打印该向量中的所有值。我会使用:

int arr_size = arr.size();
for(int i=0; i<arr_size; ++i) {//print the values}

或以这种方式实现它:

for(int i=0; i<arr.size(); ++i) {//print the values}

在我看来,第一种实现方式是将向量的大小获取到缓存中,从而使条件在第一次未命中后更快。第二次实现呢?慢吗?系统会在每次满足条件时调用 size(( 方法吗?

编辑:假设它正在使用C++。

推广带有树形体的循环,您给出的两个变体之间存在一个关键区别:如果arr的大小在循环过程中发生变化怎么办?

对于第二种情况,如果编译器可以假设它不会更改,那么它可以优化循环,以便只调用一次arr.size()并且生成的代码与第一种情况大致相同。

但是,如果循环体调用外部函数(极有可能(,那么它就不能再做出这种假设,并且必须检查arr.size()每个循环迭代。

话虽如此,arr.size()可能会解决一个简单的结构成员访问,这不会比将值存储在局部变量中慢,因此无论如何使用第一个变体都没有太多好处。 除非arr是指针或引用,在这种情况下它是间接的,然后是访问,所以第一个版本会快一点。

如果这是一个特别常见的运行循环,并且由于某种原因您必须在没有优化的情况下进行编译,则可能需要使用第一种情况来加快速度。

但是,代码的可读性并没有因为多一行而受到太大损害,是吗?

总而言之,我会选择变体

2,除非循环是一个必须紧的内部循环,在这种情况下,我会选择变体 1 以确保。

当然,如果将元素添加到循环内部的arr并且循环需要覆盖这些元素,那么只有第二个变体是正确的。

我建议你是否可能使用迭代器而不是索引。 例如:

在 C++ 中:

for( const_iterator it = arr.begin(), ite = arr.end();
     it != ite; ++it)
{
 ....
}

在 c# 中:

foreach(var item in arr){....}

c++的一个优点是当你有list而不是vector时,在vector size((中是O(1(,但在list中它是O(n(。此外,这可以防止调用的情况,arr。大小((太多次。

通常的优点是 C# 和 C++ 中的代码更具可读性,但在某些情况下仍然无法使用它们,您应该使用索引。

第二个选项更好:

for(int i=0; i<arr.size(); ++i) {//print the values}

循环结束后将释放变量 i。arr.size(( 将在循环初始化后计算。不会分配内存来存储arr_size变量。

如果你有一个足够现代的编译器:

for (auto i: arr)
{
    //print the values
}

或者更好的是...避免滚动自己的for循环(这也适用于 C++11 之前的编译器(:

std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ","));
  • std::copy()正在<algorithm>
  • std::ostream_iterator<><iterator>.

我做了一些测试,缓存这些值似乎比每次迭代评估条件要好[略好]。

这是我使用 std::vector 时的测试结果。

代码:使用 std::vector 测试 for 循环缓存计时结果(评估和缓存运行各运行 4 次(:

Evaluated:
- Compilation time: 2,16 sec, absolute running time: 10,94 sec, absolute service time: 13,11 sec
- Compilation time: 1,76 sec, absolute running time: 9,98 sec, absolute service time: 11,75 sec
- Compilation time: 1,76 sec, absolute running time: 10,11 sec, absolute service time: 11,88 sec
- Compilation time: 1,91 sec, absolute running time: 10,62 sec, absolute service time: 12,53 sec
Cached:
 - Compilation time: 1,84 sec, absolute running time: 9,55 sec, absolute
   service time: 11,39 sec
 - Compilation time: 1,75 sec, absolute running
   time: 9,85 sec, absolute service time: 11,61 sec
 - Compilation time:
   1,83 sec, absolute running time: 9,41 sec, absolute service time:
   11,25 sec
 - Compilation time: 1,86 sec, absolute running time: 9,87
   sec, absolute service time: 11,73 sec

这是我使用 std::list 时的测试结果。

代码:使用 std::list 测试 for 循环缓存计时结果(评估和缓存运行各 2 次运行(:

Evaluated:
 - Compilation time: 1,9 sec, absolute running time: 17,94 sec, absolute service time: 19,84 sec
 - Compilation time: 1,84 sec, absolute running time: 17,52 sec, absolute service time: 19,36 sec
Cached:
 - Compilation time: 1,81 sec, absolute running time: 17,74 sec, absolute service time: 19,56 sec
 - Compilation time: 1,92 sec, absolute running time: 17,29 sec, absolute service time: 19,22 sec

绝对运行时间是我用作比较指标的指标。缓存条件始终(但略微(优于评估条件。