【问题标题】:Is there any way to optimize c++ string += operator?有没有办法优化 c++ 字符串 += 运算符?
【发布时间】:2020-11-30 16:28:53
【问题描述】:

英文不好,但请理解。

string str;
string str_base = "user name = ";
string str_user_input;
string str_system_message;
...

str = str_base + str_user_input + "\n [system message :]" + str_system_message;

cout << str << endl;

我正在使用这样的现有代码,有没有办法优化字符串?

我认为这段代码做了很多无用的操作。有没有办法优化?

【问题讨论】:

  • 是的,使用std::ostringstream
  • @Andy 上次我用 stringstream 和 string::operator+ 比较了连接的性能,后者更快。每次人们不相信我时,他们都会比较自己并得到相同的结果。也许我们做错了什么,但没有人能告诉我 stringstream 更好。
  • 如果你只想输出拼接结果,那么直接输出碎片即可:cout &lt;&lt; str_base &lt;&lt; str_user_input &lt;&lt; "\n [system message :]" &lt;&lt; str_system_message &lt;&lt; endl;
  • 使用 C++20:std::format("{}{}\n [system message :]{}", str_base, str_user_input, str_system_message); 否则:fmt::format("{}{}\n [system message :]{}", str_base, str_user_input, str_system_message);
  • 为什么要优化这个特定的代码?它是否在分析过程中显示为重要的处理瓶颈? cout 电话可能比这里的任何其他线路都贵得多。

标签: c++ string optimization operator-keyword


【解决方案1】:

您的问题是 +=,但您没有在任何地方使用 +=。您只使用 +。

"+" 可能是连接字符串的最有效方式。还有其他方法,但 + 不太可能更糟。

正如 John Bollinger 所说,如果你需要做的只是输出连接的结果,那么直接输出碎片:

cout << str_base << str_user_input << "\n [system message :]" << str_system_message << endl;

或者使用 C++20(正如 Thomas Sablik 所说):

std::format("{}{}\n [system message :]{}", str_base, str_user_input, str_system_message); otherwise: fmt::format("{}{}\n [system message :]{}", str_base, str_user_input, str_system_message);

我建议尝试优化代码的其他部分(如果需要),因为它不太可能比语言/编译器做得更好。忘记优化+。

换个角度看这个问题的答案:

Efficient string concatenation in C++

【讨论】:

  • @phuclv 有时你应该使用\n,有时你应该使用endl。您提供的链接提供了一些很好的建议,比您的评论更细致入微。
【解决方案2】:

我认为这段代码做了很多无用的操作。有没有办法优化?

不要猜测,而是通过分析来衡量。

也许(至少在 Linux 系统上)带有实用程序,例如 gprof(1)perf(1)time(1),或与 time(7) 相关的函数,例如 clock_gettime(2)。至少你会发现类似的东西for Windows 和 MacOSX 和 Android。大多数计算机都有一些类似于HPET 的硬件。另请参阅OSDEV 了解更多信息。

如果您使用最新的GCC 编译器,请务必启用optimizations。所以在使用gprof(1)之前编译和链接with至少g++ -Wall -pg -O2 -flto。还要学习使用GDB 调试器(或另一个)来观察程序的行为(它的operational semantics)。

您可能会对最近的 GCC 10 编译器能够进行的优化(在 2020 年夏季)感到惊讶,因为即使在 inline 未询问时它也会执行 inline expansion。如果您碰巧了解汇编代码,请尝试使用命令行g++ -O3 -fverbose-asm -S foo.cfoo.cc 中编译您的C++ 代码,然后查看生成的foo.s 文件。

当然,阅读好的C++ programming book 并查看this C++ reference 网站(以及n3337,一个C++ 标准)。并阅读您的 C++ 编译器(和链接器)的文档。

我认为这段代码做了很多无用的操作。有没有办法优化?

将此类微优化留给您的 C++ 编译器。

首先确保您的代码正确,然后花精力进行分析和优化。

当您想到这一点时,大多数计算机都会花时间做很多无用的操作。阅读blog of the late J.Pitrat 和他的Artificial beings book

作为一名软件开发人员,您的职责是平衡您的开发工作与计算机时间。今天,计算机在大多数情况下都比软件开发人员便宜

如果原始性能非常重要,请花时间编写汇编代码。如果使用 Linux,请阅读 Linux Assembly HowTo。准备好比 C++ 低 10 倍的生产力....

如果性能很重要,还可以考虑进行一些metaprogramming 和运行时代码生成(例如使用asmjitlibgccjit,或者像SBCL 那样)。阅读有关partial evaluation and automatic program generation 的更多信息,另请阅读Dragon Book 和一些Introduction to Algorithms

Another answer 说:

优化问题乍一看似乎微不足道

当然不是微不足道的。注意Rice's theorem

我认为这段代码做了很多无用的操作。有没有办法优化?

大概吧。考虑machine learning 优化方法,例如MILEPOST GCCCtuning 项目。在许多开源项目(包括CHARIOTGCCClangRefPerSysFrama-CQtANTLRSWIG)中查看(至少是为了获得灵感)生成分析 C++代码。

重要的问题是经济问题:将代码优化 1% 是否值得您花时间(例如,花费 几个月 的努力,也许写您的 GCC plugin)来优化您的代码?在某些情况下,付出努力是值得的,但在大多数情况下并非如此。

【讨论】:

    【解决方案3】:

    简单地说,有一些方法可以优化这个:

    首先,通过使用 += 而不是多个 + 操作,您将避免创建一些临时对象。

    也就是说,更喜欢这样做:

    s += s1;
    s += s2;
    s += s3;
    

    代替:

    s = s1 + s2 + s3;
    

    其次,可以在调用(上面的 += 示例)之前将字符串的大小相加并在 s 中保留内存。

    也就是说(我确实提到这是一个“简单”的答案),这里有一些其他注意事项:

    • 语言设计者和编译器开发者已经花费了很多时间来优化字符串操作,并且你不太可能通过在处理字符串和用户输入的函数中进行微优化来显着优化你的代码(除非字符串非常大,除非这是关键路径上的代码,除非您在一个非常受限的系统中工作)。

    • 您可能被否决了,因为看起来您正在关注要解决的错误问题。

    • 优化问题乍一看似乎微不足道,但在您设定性能目标和衡量当前性能的方法之前,您可能会在错误的地方寻找优化(看起来您现在正在这样做)。

    【讨论】:

      猜你喜欢
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多