【问题标题】:Range-based for loop, which one is faster?基于范围的for循环,哪个更快?
【发布时间】:2017-01-03 12:27:05
【问题描述】:

如果我们对字符串使用基于范围的 for 循环,使用会有什么好处

for (auto const & c : s)

结束

for (auto c : s)

// c => char
// s => std::string

我问这个是因为内存中只有一个字节的字符复制起来并不昂贵,这让我昨晚很好奇。

我做了一些基准测试!

结果:

// In Milliseconds

// 1000
// BY COPY: 7
// BY _REF: 5

// 10000
// BY COPY: 51
// BY _REF: 50

// 100000
// BY COPY: 503
// BY _REF: 501

// 1000000
// BY COPY: 5047
// BY _REF: 5101

// 10000000
// BY COPY: 52058
// BY _REF: 56160

代码:

#include <chrono>
#include <iostream>
#include <string>

using std::cout;
using std::endl;

bool by_copy(std::string const & s);
bool by_const_ref(std::string const & s);

int main() {
    std::string const test {"0000000001"};

    auto start {std::chrono::steady_clock::now()};
    for (unsigned long long i {}; i < 10000000; ++i) {
        bool b {by_copy(test)};
        if (b) {}
    }
    auto end {std::chrono::steady_clock::now()};
    auto duration {std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()};
    cout << "BY COPY: " << duration << '\n';

    start = std::chrono::steady_clock::now();
    for (unsigned long long i {}; i < 10000000; ++i) {
        bool b {by_const_ref(test)};
        if (b) {}
    }
    end = std::chrono::steady_clock::now();
    duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    cout << "BY _REF: " << duration << '\n';

    return 0;
}

bool by_copy(std::string const & s) {
    for (auto c : s) {
        if (c == '1') {
            return true;
        }
    }
    return false;
}

bool by_const_ref(std::string const & s) {
    for (auto const & c : s) {
        if (c == '1') {
            return true;
        }
    }
    return false;
}

更新

出于好奇,我还按索引进行了基准测试,它比基于范围的 for 循环快得多,为什么?

结果

    // 1000
    // BY COPY: 7
    // BY _REF: 5
    // BYINDEX: 4

    // 10000
    // BY COPY: 59
    // BY _REF: 58
    // BYINDEX: 37

    // 100000
    // BY COPY: 526
    // BY _REF: 495
    // BYINDEX: 326

    // 1000000
    // BY COPY: 5751
    // BY _REF: 5038
    // BYINDEX: 3308

    // 10000000
    // BY COPY: 62202
    // BY _REF: 63002
    // BYINDEX: 38744

by_index 函数:

bool by_index(std::string const & s) {
    for (size_t i {}; i < s.size(); ++i) {
        if (s[i] == '1') {
            return true;
        }
    }
    return false;
}

【问题讨论】:

  • 当你测量差异时,你发现了什么?
  • @KerrekSB 有趣的是,没有测量工作的问题如何被发送到测量,而测量工作的问题被告知他们的测量毫无意义,只有拆卸很重要:)
  • 为每个生成的代码:godbolt.org/g/b0VZeO - 玩“发现差异”!
  • @Rotem 那是因为你通常应该两者都做。首先检查反汇编,看看生成的代码是否不同。如果没有,测量是没有意义的,否则它是必不可少的。这个问题缺乏双方的研究努力。
  • @Rotem:这可能过于简单化了。有很多不同类型的问题。

标签: c++ string for-loop char


【解决方案1】:

为了澄清,我将您的问题解释为迭代字符串的字符 - 而不是迭代字符串容器。

不,没有优势。事实上,由于隐含的间接性,理论上存在引用变慢的可能性。但是,这两种变体很可能会编译为完全相同的机器代码,因为体面的优化器将能够避免间接寻址。

【讨论】:

  • 第二种情况下没有调用字符串构造函数,而第一种情况下没有?
  • @RawN 如果s 是一个字符串,那么c 是一个字符。那里没有构造函数。
  • @RawN 不,在这两种情况下都没有构造字符串。
  • 我明白了,自动被评估为 char 所以不需要调用字符串构造函数,如果我正确理解的话。
  • @RawN 是的。 c 具有s 的元素类型。不是s 的类型。 std::string 元素的类型为 char
猜你喜欢
  • 2016-10-31
  • 1970-01-01
  • 2014-12-06
  • 2014-01-12
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多