在循环中使用 string.length() 是否高效?

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

例如,假设

string s
是这样的:

for(int x = 0; x < s.length(); x++)

比这个更好?:

int length = s.length();
for(int x = 0; x < length; x++)
c++ string compiler-optimization loop-invariant
6个回答
15
投票

一般来说,如果结果在迭代过程中没有改变,您应该避免在循环的条件部分中调用函数。

因此规范形式为:

for (std::size_t x = 0, length = s.length(); x != length; ++x);

这里请注意 3 件事:

  • 初始化可以初始化多个变量
  • 条件用
    !=
    表示,而不是
    <
  • 我使用前增量而不是后增量

(我还更改了类型,因为负长度是无意义的,并且字符串接口是根据

std::string::size_type
定义的,在大多数实现中通常是
std::size_t
)。

虽然......我承认它对性能的影响不如对可读性的影响:

  • 双重初始化意味着
    x
    length
    范围都尽可能严格
  • 通过记住结果,读者不会怀疑迭代过程中长度是否会变化
  • 当您不需要使用“旧”值创建临时值时,使用预增量通常会更好

简而言之:使用最好的工具来完成手头的工作:)


5
投票

取决于编译器的内联和优化能力。一般来说,第二个变体很可能会更快(更好:它会更快或与第一个片段一样快,但几乎不会慢)。

但是,在大多数情况下这并不重要,因此人们往往更喜欢第一个变体,因为它比较短。


4
投票

这取决于您的 C++ 实现/库,唯一确定的方法是对其进行基准测试。然而,可以肯定的是,第二个版本永远不会比第一个版本慢,因此,如果您不在循环内修改字符串,那么这是一个明智的优化。


1
投票

您想要多高效?

如果不在循环内修改字符串,编译器很容易发现大小没有改变。不要让它变得比你需要的更复杂!


1
投票

虽然我不一定鼓励您这样做,但令人惊讶的是,不断调用

.length()
比将其存储在
int
中更快(至少在我的计算机上,请记住我正在使用MSI配备 i5 第四代的游戏笔记本电脑,但它不应该真正影响哪种方式更快)。

持续调用的测试代码:

#include <iostream>

using namespace std;

int main()
{
    string g = "01234567890";
    for(unsigned int rep = 0; rep < 25; rep++)
    {
        g += g;
    }//for loop used to double the length 25 times.
    int a = 0;
    //int b = g.length();
    for(unsigned int rep = 0; rep < g.length(); rep++)
    {
        a++;
    }
    return a;
}

根据 Code::Blocks,平均运行时间为 385 毫秒

这是将长度存储在变量中的代码:

#include <iostream>

using namespace std;

int main()
{
    string g = "01234567890";
    for(unsigned int rep = 0; rep < 25; rep++)
    {
        g += g;
    }//for loop used to double the length 25 times.
    int a = 0;
    int b = g.length();
    for(unsigned int rep = 0; rep < b; rep++)
    {
        a++;
    }
    return a;
}

平均约为 420 毫秒。

我知道这个问题已经有一个公认的答案,但还没有任何经过实际测试的答案,所以我决定投入 2 美分。我和你有同样的问题,但我在这里没有找到任何有用的答案,所以我做了自己的实验。


0
投票

s.length() 是内联并返回成员变量吗?那么不,否则取消引用并将内容放入堆栈的成本,您知道每次迭代都会产生函数调用的所有开销。

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