【问题标题】:Is using string.length() in loop efficient?在循环中使用 string.length() 是否有效?
【发布时间】:2011-07-05 08:26:32
【问题描述】:

例如,假设string s 是这样的:

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

比这更好?:

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

谢谢, 乔尔

【问题讨论】:

  • 第一个涉及每次循环迭代的函数调用开销,而不是仅一次。据我所知,.length() 方法 可能 会导致不平凡的计算(例如,在字符串上循环寻找终止字符),尽管这在任何实际实现中都极不可能,AFAICT。
  • 我不完全确定(因为我不熟悉 STL 字符串的实现),但是,在我看来,除了 int length 会花费你 @ 987654326@ 更多内存。这是假设s.length() 只返回一个已存储在结构中的整数值。
  • @Tim:我认为.length 保证为O(1),因为std::string 符合Sequence 的要求。
  • 我问这个问题是因为我在一些博客上读到“永远不要在循环中的条件中使用 s.length(),因为它每次都必须搜索字符串以找到 NULL 终止符。”只是想知道这是否正确。
  • @Joel strlen() 是这样,但是 string.length() 不能使用 nul 终止符以明显的方式实现,因为 std::string 允许 nul(零)字节在字符串。

标签: c++ string optimization


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    因此,规范形式是:

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

    这里注意三点:

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

    (我也改变了类型,因为负长度是无意义的,字符串接口是用std::string::size_type定义的,在大多数实现中通常是std::size_t)。

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

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

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

    【讨论】:

    • 和 (4),length 返回一个 size_t
    【解决方案3】:

    这取决于编译器的内联和优化能力。通常,第二个变体很可能会更快(更好:它会更快或与第一个 sn-p 一样快,但几乎不会变慢)。

    但是,在大多数情况下,这并不重要,因此人们倾向于选择第一个变体,因为它很短。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        你想提高多少效率?

        如果你不修改循环内的字符串,编译器很容易看到大小没有改变。不要让它变得比你必须做的更复杂!

        【讨论】:

          【解决方案6】:

          虽然我不一定鼓励您这样做,但似乎不断调用 .length() 比将其存储在 int 中更快,令人惊讶的是(至少在我的计算机上,请记住我正在使用带有 i5 4th gen 的 MSI 游戏笔记本电脑,但它不应该真正影响哪种方式更快)。

          常量调用的测试代码:

          #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 美分。我和你有同样的问题,但我没有发现任何帮助答案在这里,所以我进行了自己的实验。

          【讨论】:

            猜你喜欢
            • 2014-07-03
            • 1970-01-01
            • 1970-01-01
            • 2020-07-29
            • 1970-01-01
            • 1970-01-01
            • 2021-02-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多