【问题标题】:Why does emplace_back("Hello") call strlen?为什么 emplace_back("Hello") 调用 strlen?
【发布时间】:2018-07-07 03:53:49
【问题描述】:

Justin's answer 在另一个问题上做了一个我觉得很有趣但不能完全解释的观察。考虑以下代码:

std::vector<std::string> v;
v.push_back("Hello, world!");  // Doesn't call strlen.
v.emplace_back("Hello, world!");  // Calls strlen.

如果您查看程序集,emplace_back generates a call to strlen,而 push_back does not(在 gcc 8.1 和 clang 6.0 中使用 -Ofast 测试)。

为什么会这样?为什么emplace_back 不能在这里优化strlen 调用?我最初的想法是 push_back 隐式创建 std::string before 函数调用(因此 std::string 构造函数直接传递字符串文字,这是最佳处理),而 emplace_back在函数调用之后创建std::string (所以std::string 构造函数被转发字符串文字,我认为它已经从const char [N] 衰减到@987654340 @,因此需要strlen 调用)。

但是emplace_back takes a T&amp;&amp; parametermy tests show that the string literal shouldn't be decaying to a pointer here。显然我忽略了一些东西。

【问题讨论】:

  • 您是否注意到strlen() 调用仅在需要调整矢量大小时发生?在size() &lt; capacity() 的正常情况下,不会调用strlen()。所以在性能方面这并没有什么区别,因为只有慢速路径有 strlen() 调用,而且由于许多其他原因它很慢。
  • @BasileStarynkevitch:不只是 GCC。 clang 和 libc++ 也会发生同样的事情。我问是因为我很好奇。
  • @Cornstalks:那么我认为接下来你应该阅读汇编代码并弄清楚编译器在调用strlen()时正在做什么。
  • 并非所有const char [N]s 都是字符串文字。
  • 而且你不能假设const char [N] 不会有'\0' 之前结束。

标签: c++ stdvector stdstring


【解决方案1】:

strlen 调用在慢速路径的外联函数体中;该函数体必须对const char (&amp;)[42] 类型的所有参数(在您的godbolt 示例中)有效,包括并非源自没有嵌入空值的41 个字符的字符串文字的参数。

快速路径内联到foo,它会在编译时计算长度。

【讨论】:

    猜你喜欢
    • 2014-03-05
    • 2013-08-18
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 2012-02-05
    • 2012-06-09
    • 2011-10-14
    相关资源
    最近更新 更多